Coverage Report

Created: 2026-08-14 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/src/server/ua_nodes.c
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
 *
5
 *    Copyright 2015-2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
6
 *    Copyright 2015-2016 (c) Sten GrĂ¼ner
7
 *    Copyright 2015 (c) Chris Iatrou
8
 *    Copyright 2015, 2017 (c) Florian Palm
9
 *    Copyright 2015 (c) Oleksiy Vasylyev
10
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
11
 *    Copyright 2017 (c) Julian Grothoff
12
 */
13
14
#include "ua_server_internal.h"
15
#include "../ua_types_encoding_binary.h"
16
17
/*********************/
18
/* ReferenceType Set */
19
/*********************/
20
21
#define UA_REFTYPES_ALL_MASK (~(UA_UInt32)0)
22
#define UA_REFTYPES_ALL_MASK2 UA_REFTYPES_ALL_MASK, UA_REFTYPES_ALL_MASK
23
#define UA_REFTYPES_ALL_MASK4 UA_REFTYPES_ALL_MASK2, UA_REFTYPES_ALL_MASK2
24
#if UA_REFERENCETYPESET_MAX / 32 > 8
25
# error Adjust macros to support than 256 reference types
26
#elif UA_REFERENCETYPESET_MAX / 32 == 8
27
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4, UA_REFTYPES_ALL_MASK4
28
#elif UA_REFERENCETYPESET_MAX / 32 == 7
29
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4, UA_REFTYPES_ALL_MASK2, UA_REFTYPES_ALL_MASK
30
#elif UA_REFERENCETYPESET_MAX / 32 == 6
31
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4, UA_REFTYPES_ALL_MASK2
32
#elif UA_REFERENCETYPESET_MAX / 32 == 5
33
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4, UA_REFTYPES_ALL_MASK
34
#elif UA_REFERENCETYPESET_MAX / 32 == 4
35
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4
36
#elif UA_REFERENCETYPESET_MAX / 32 == 3
37
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK2, UA_REFTYPES_ALL_MASK
38
#elif UA_REFERENCETYPESET_MAX / 32 == 2
39
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK2
40
#else
41
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK
42
#endif
43
44
const UA_ReferenceTypeSet UA_REFERENCETYPESET_NONE = {{0}};
45
const UA_ReferenceTypeSet UA_REFERENCETYPESET_ALL = {{UA_REFTYPES_ALL_ARRAY}};
46
47
/*****************/
48
/* Node Pointers */
49
/*****************/
50
51
3.60G
#define UA_NODEPOINTER_MASK 0x03
52
465M
#define UA_NODEPOINTER_TAG_IMMEDIATE 0x00
53
1.18M
#define UA_NODEPOINTER_TAG_NODEID 0x01
54
771M
#define UA_NODEPOINTER_TAG_EXPANDEDNODEID 0x02
55
1.90G
#define UA_NODEPOINTER_TAG_NODE 0x03
56
57
void
58
79.1M
UA_NodePointer_clear(UA_NodePointer *np) {
59
79.1M
    switch(np->immediate & UA_NODEPOINTER_MASK) {
60
42.5k
    case UA_NODEPOINTER_TAG_NODEID:
61
42.5k
        np->immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
62
42.5k
        UA_NodeId_delete((UA_NodeId*)(uintptr_t)np->id);
63
42.5k
        break;
64
1
    case UA_NODEPOINTER_TAG_EXPANDEDNODEID:
65
1
        np->immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
66
1
        UA_ExpandedNodeId_delete((UA_ExpandedNodeId*)(uintptr_t)
67
1
                                 np->expandedId);
68
1
        break;
69
79.1M
    default:
70
79.1M
        break;
71
79.1M
    }
72
79.1M
    UA_NodePointer_init(np);
73
79.1M
}
74
75
UA_StatusCode
76
79.1M
UA_NodePointer_copy(UA_NodePointer in, UA_NodePointer *out) {
77
79.1M
    UA_StatusCode res = UA_STATUSCODE_GOOD;
78
79.1M
    UA_Byte tag = in.immediate & UA_NODEPOINTER_MASK;
79
79.1M
    in.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
80
79.1M
    switch(tag) {
81
0
    case UA_NODEPOINTER_TAG_NODE:
82
0
        in.id = &in.node->nodeId;
83
0
        goto nodeid; /* fallthrough */
84
42.5k
    case UA_NODEPOINTER_TAG_NODEID:
85
42.5k
    nodeid:
86
42.5k
        out->id = UA_NodeId_new();
87
42.5k
        if(!out->id)
88
0
            return UA_STATUSCODE_BADOUTOFMEMORY;
89
42.5k
        res = UA_NodeId_copy(in.id, (UA_NodeId*)(uintptr_t)out->id);
90
42.5k
        if(res != UA_STATUSCODE_GOOD) {
91
0
            UA_free((void*)out->immediate);
92
0
            out->immediate = 0;
93
0
            break;
94
0
        }
95
42.5k
        out->immediate |= UA_NODEPOINTER_TAG_NODEID;
96
42.5k
        break;
97
1
    case UA_NODEPOINTER_TAG_EXPANDEDNODEID:
98
1
        out->expandedId = UA_ExpandedNodeId_new();
99
1
        if(!out->expandedId)
100
0
            return UA_STATUSCODE_BADOUTOFMEMORY;
101
1
        res = UA_ExpandedNodeId_copy(in.expandedId,
102
1
                                     (UA_ExpandedNodeId*)(uintptr_t)
103
1
                                     out->expandedId);
104
1
        if(res != UA_STATUSCODE_GOOD) {
105
0
            UA_free((void*)out->immediate);
106
0
            out->immediate = 0;
107
0
            break;
108
0
        }
109
1
        out->immediate |= UA_NODEPOINTER_TAG_EXPANDEDNODEID;
110
1
        break;
111
0
    default:
112
79.1M
    case UA_NODEPOINTER_TAG_IMMEDIATE:
113
79.1M
        *out = in;
114
79.1M
        break;
115
79.1M
    }
116
79.1M
    return res;
117
79.1M
}
118
119
UA_Boolean
120
694M
UA_NodePointer_isLocal(UA_NodePointer np) {
121
694M
    UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK;
122
694M
    return (tag != UA_NODEPOINTER_TAG_EXPANDEDNODEID);
123
694M
}
124
125
UA_Order
126
937M
UA_NodePointer_order(UA_NodePointer p1, UA_NodePointer p2) {
127
937M
    if(p1.immediate == p2.immediate)
128
24.8M
        return UA_ORDER_EQ;
129
130
    /* Extract the tag and resolve pointers to nodes */
131
912M
    UA_Byte tag1 = p1.immediate & UA_NODEPOINTER_MASK;
132
912M
    if(tag1 == UA_NODEPOINTER_TAG_NODE) {
133
0
        p1 = UA_NodePointer_fromNodeId(&p1.node->nodeId);
134
0
        tag1 = p1.immediate & UA_NODEPOINTER_MASK;
135
0
    }
136
912M
    UA_Byte tag2 = p2.immediate & UA_NODEPOINTER_MASK;
137
912M
    if(tag2 == UA_NODEPOINTER_TAG_NODE) {
138
0
        p2 = UA_NodePointer_fromNodeId(&p2.node->nodeId);
139
0
        tag2 = p2.immediate & UA_NODEPOINTER_MASK;
140
0
    }
141
142
    /* Different tags, cannot be identical */
143
912M
    if(tag1 != tag2)
144
6.98M
        return (tag1 > tag2) ? UA_ORDER_MORE : UA_ORDER_LESS;
145
146
    /* Immediate */
147
905M
    if(UA_LIKELY(tag1 == UA_NODEPOINTER_TAG_IMMEDIATE))
148
905M
        return (p1.immediate > p2.immediate) ?
149
714M
            UA_ORDER_MORE : UA_ORDER_LESS;
150
151
    /* Compare from pointers */
152
88.1k
    p1.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
153
88.1k
    p2.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
154
88.1k
    if(tag1 == UA_NODEPOINTER_TAG_EXPANDEDNODEID)
155
0
        return UA_ExpandedNodeId_order(p1.expandedId, p2.expandedId);
156
88.1k
    return UA_NodeId_order(p1.id, p2.id);
157
88.1k
}
158
159
UA_NodePointer
160
272M
UA_NodePointer_fromNodeId(const UA_NodeId *id) {
161
272M
    UA_NodePointer np;
162
272M
    if(id->identifierType != UA_NODEIDTYPE_NUMERIC) {
163
113k
        np.id = id;
164
113k
        np.immediate |= UA_NODEPOINTER_TAG_NODEID;
165
113k
        return np;
166
113k
    }
167
168
272M
#if SIZE_MAX > UA_UINT32_MAX
169
    /* 64bit: 4 Byte for the numeric identifier + 2 Byte for the namespaceIndex
170
     *        + 1 Byte for the tagging bit (zero) */
171
272M
    np.immediate  = ((uintptr_t)id->identifier.numeric) << 32;
172
272M
    np.immediate |= ((uintptr_t)id->namespaceIndex) << 8;
173
#else
174
    /* 32bit: 3 Byte for the numeric identifier + 6 Bit for the namespaceIndex
175
     *        + 2 Bit for the tagging bit (zero) */
176
    if(id->namespaceIndex < (0x01 << 6) &&
177
       id->identifier.numeric < (0x01 << 24)) {
178
        np.immediate  = ((uintptr_t)id->identifier.numeric) << 8;
179
        np.immediate |= ((uintptr_t)id->namespaceIndex) << 2;
180
    } else {
181
        np.id = id;
182
        np.immediate |= UA_NODEPOINTER_TAG_NODEID;
183
    }
184
#endif
185
272M
    return np;
186
272M
}
187
188
UA_NodeId
189
387M
UA_NodePointer_toNodeId(UA_NodePointer np) {
190
387M
    UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK;
191
387M
    np.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
192
387M
    switch(tag) {
193
0
    case UA_NODEPOINTER_TAG_NODE:
194
0
        return np.node->nodeId;
195
944k
    case UA_NODEPOINTER_TAG_NODEID:
196
944k
        return *np.id;
197
0
    case UA_NODEPOINTER_TAG_EXPANDEDNODEID:
198
0
        return np.expandedId->nodeId;
199
0
    default:
200
386M
    case UA_NODEPOINTER_TAG_IMMEDIATE:
201
386M
        break;
202
387M
    }
203
204
386M
    UA_NodeId id;
205
386M
    id.identifierType = UA_NODEIDTYPE_NUMERIC;
206
#if SIZE_MAX > UA_UINT32_MAX /* 64bit */
207
386M
    id.namespaceIndex = (UA_UInt16)(np.immediate >> 8);
208
386M
    id.identifier.numeric = (UA_UInt32)(np.immediate >> 32);
209
#else                        /* 32bit */
210
    id.namespaceIndex = ((UA_Byte)np.immediate) >> 2;
211
    id.identifier.numeric = np.immediate >> 8;
212
#endif
213
386M
    return id;
214
387M
}
215
216
UA_NodePointer
217
177M
UA_NodePointer_fromExpandedNodeId(const UA_ExpandedNodeId *id) {
218
177M
    if(!UA_ExpandedNodeId_isLocal(id)) {
219
1
        UA_NodePointer np;
220
1
        np.expandedId = id;
221
1
        np.immediate |= UA_NODEPOINTER_TAG_EXPANDEDNODEID;
222
1
        return np;
223
1
    }
224
177M
    return UA_NodePointer_fromNodeId(&id->nodeId);
225
177M
}
226
227
UA_ExpandedNodeId
228
76.4M
UA_NodePointer_toExpandedNodeId(UA_NodePointer np) {
229
    /* Resolve node pointer to get the NodeId */
230
76.4M
    UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK;
231
76.4M
    if(tag == UA_NODEPOINTER_TAG_NODE) {
232
0
        np = UA_NodePointer_fromNodeId(&np.node->nodeId);
233
0
        tag = np.immediate & UA_NODEPOINTER_MASK;
234
0
    }
235
236
    /* ExpandedNodeId, make a shallow copy */
237
76.4M
    if(tag == UA_NODEPOINTER_TAG_EXPANDEDNODEID) {
238
0
        np.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
239
0
        return *np.expandedId;
240
0
    }
241
242
    /* NodeId, either immediate or via a pointer */
243
76.4M
    UA_ExpandedNodeId en;
244
76.4M
    UA_ExpandedNodeId_init(&en);
245
76.4M
    en.nodeId = UA_NodePointer_toNodeId(np);
246
76.4M
    return en;
247
76.4M
}
248
249
/**************/
250
/* References */
251
/**************/
252
253
static UA_StatusCode
254
addReferenceTarget(UA_NodeReferenceKind *refs, UA_NodePointer target,
255
                   UA_UInt32 targetNameHash);
256
257
static UA_StatusCode
258
addReferenceTargetToTree(UA_NodeReferenceKind *rk, UA_NodePointer targetId,
259
                         UA_UInt32 targetIdHash, UA_UInt32 targetNameHash);
260
261
enum ZIP_CMP
262
384M
cmpRefTargetId(const void *a, const void *b) {
263
384M
    const UA_ReferenceTargetTreeElem *aa = (const UA_ReferenceTargetTreeElem*)a;
264
384M
    const UA_ReferenceTargetTreeElem *bb = (const UA_ReferenceTargetTreeElem*)b;
265
384M
    if(aa->targetIdHash < bb->targetIdHash)
266
190M
        return ZIP_CMP_LESS;
267
194M
    if(aa->targetIdHash > bb->targetIdHash)
268
193M
        return ZIP_CMP_MORE;
269
799k
    return (enum ZIP_CMP)UA_NodePointer_order(aa->target.targetId,
270
799k
                                              bb->target.targetId);
271
194M
}
272
273
enum ZIP_CMP
274
196M
cmpRefTargetName(const void *a, const void *b) {
275
196M
    const UA_ReferenceTarget *aa = (const UA_ReferenceTarget*)a;
276
196M
    const UA_ReferenceTarget *bb = (const UA_ReferenceTarget*)b;
277
196M
    if(aa->targetNameHash == bb->targetNameHash)
278
22.1M
        return ZIP_CMP_EQ;
279
174M
    return (aa->targetNameHash < bb->targetNameHash) ?
280
89.7M
        ZIP_CMP_LESS : ZIP_CMP_MORE;
281
196M
}
282
283
/* Move to the array in-order, also deletes the tree elements */
284
static void
285
moveTreeToArray(UA_ReferenceTarget *array, size_t *pos,
286
0
                UA_ReferenceTargetTreeElem *elem) {
287
0
    if(!elem)
288
0
        return;
289
0
    moveTreeToArray(array, pos, elem->idTreeEntry.left);
290
0
    array[*pos] = elem->target;
291
0
    (*pos)++;
292
0
    moveTreeToArray(array, pos, elem->idTreeEntry.right);
293
0
    UA_free(elem);
294
0
}
295
296
static void *
297
23.6M
removeTreeEntry(void *context, UA_ReferenceTargetTreeElem *elem) {
298
23.6M
    (void)context;
299
23.6M
    UA_NodePointer_clear(&elem->target.targetId);
300
23.6M
    UA_free(elem);
301
23.6M
    return NULL;
302
23.6M
}
303
304
UA_StatusCode
305
222k
UA_NodeReferenceKind_switch(UA_NodeReferenceKind *rk) {
306
222k
    UA_assert(rk->targetsSize > 0);
307
308
222k
    if(rk->hasRefTree) {
309
        /* From tree to array */
310
0
        UA_ReferenceTarget *array = (UA_ReferenceTarget*)
311
0
            UA_malloc(sizeof(UA_ReferenceTarget) * rk->targetsSize);
312
0
        if(!array)
313
0
            return UA_STATUSCODE_BADOUTOFMEMORY;
314
0
        size_t pos = 0;
315
0
        moveTreeToArray(array, &pos, rk->targets.tree.idRoot);
316
0
        rk->targets.array = array;
317
0
        rk->hasRefTree = false;
318
0
        return UA_STATUSCODE_GOOD;
319
0
    }
320
321
    /* From array to tree */
322
222k
    UA_NodeReferenceKind newRk = *rk;
323
222k
    newRk.hasRefTree = true;
324
222k
    newRk.targets.tree.idRoot = NULL;
325
222k
    newRk.targets.tree.nameRoot = NULL;
326
222k
    newRk.targetsSize = 0;
327
4.00M
    for(size_t i = 0; i < rk->targetsSize; i++) {
328
3.78M
        UA_assert(newRk.hasRefTree == true);
329
3.78M
        UA_StatusCode res =
330
3.78M
            addReferenceTarget(&newRk, rk->targets.array[i].targetId,
331
3.78M
                               rk->targets.array[i].targetNameHash);
332
3.78M
        if(res != UA_STATUSCODE_GOOD) {
333
0
            ZIP_ITER(UA_ReferenceIdTree,
334
0
                     (UA_ReferenceIdTree*)&newRk.targets.tree.idRoot,
335
0
                     removeTreeEntry, NULL);
336
0
            return res;
337
0
        }
338
3.78M
    }
339
4.00M
    for(size_t i = 0; i < rk->targetsSize; i++)
340
3.78M
        UA_NodePointer_clear(&rk->targets.array[i].targetId);
341
222k
    UA_free(rk->targets.array);
342
222k
    *rk = newRk;
343
222k
    return UA_STATUSCODE_GOOD;
344
222k
}
345
346
void *
347
UA_NodeReferenceKind_iterate(UA_NodeReferenceKind *rk,
348
                             UA_NodeReferenceKind_iterateCallback callback,
349
210M
                             void *context) {
350
210M
    if(rk->hasRefTree)
351
4.09M
        return ZIP_ITER(UA_ReferenceIdTree,
352
210M
                        (UA_ReferenceIdTree*)&rk->targets.tree.idRoot,
353
210M
                        (UA_ReferenceIdTree_cb)callback, context);
354
310M
    for(size_t i = 0; i < rk->targetsSize; i++) {
355
225M
        void *res = callback(context, &rk->targets.array[i]);
356
225M
        if(res)
357
121M
            return res;
358
225M
    }
359
85.2M
    return NULL;
360
206M
}
361
362
const UA_ReferenceTarget *
363
UA_NodeReferenceKind_findTarget(const UA_NodeReferenceKind *rk,
364
35.4M
                                const UA_ExpandedNodeId *targetId) {
365
35.4M
    UA_NodePointer targetP = UA_NodePointer_fromExpandedNodeId(targetId);
366
35.4M
    if(rk->hasRefTree) {
367
        /* Return from the tree */
368
21.4M
        UA_ReferenceTargetTreeElem tmpTarget;
369
21.4M
        tmpTarget.target.targetId = targetP;
370
21.4M
        tmpTarget.targetIdHash = UA_ExpandedNodeId_hash(targetId);
371
21.4M
        UA_ReferenceTargetTreeElem *result =
372
21.4M
            ZIP_FIND(UA_ReferenceIdTree, (UA_ReferenceIdTree*)
373
21.4M
                     (uintptr_t)&rk->targets.tree.idRoot, &tmpTarget);
374
21.4M
        if(result)
375
799k
            return &result->target;
376
21.4M
    } else {
377
        /* Return from the array */
378
72.0M
        for(size_t i = 0; i < rk->targetsSize; i++) {
379
59.2M
            if(UA_NodePointer_equal(targetP, rk->targets.array[i].targetId))
380
1.07M
                return &rk->targets.array[i];
381
59.2M
        }
382
13.9M
    }
383
33.5M
    return NULL;
384
35.4M
}
385
386
/* General node handling methods. There is no UA_Node_new() method here.
387
 * Creating nodes is part of the Nodestore layer */
388
389
15.2M
void UA_Node_clear(UA_Node *node) {
390
    /* Delete references */
391
15.2M
    UA_Node_deleteReferences(node);
392
393
    /* Delete other head content */
394
15.2M
    UA_NodeHead *head = &node->head;
395
15.2M
    UA_NodeId_clear(&head->nodeId);
396
15.2M
    UA_QualifiedName_clear(&head->browseName);
397
398
15.2M
    UA_LocalizedTextListEntry *lt;
399
400
30.4M
    while((lt = head->displayName)) {
401
15.2M
        head->displayName = lt->next;
402
15.2M
        UA_LocalizedText_clear(&lt->localizedText);
403
15.2M
        UA_free(lt);
404
15.2M
    }
405
406
15.4M
    while((lt = head->description)) {
407
214k
        head->description = lt->next;
408
214k
        UA_LocalizedText_clear(&lt->localizedText);
409
214k
        UA_free(lt);
410
214k
    }
411
412
    /* Delete unique content of the nodeclass */
413
15.2M
    switch(head->nodeClass) {
414
1.24M
    case UA_NODECLASS_OBJECT:
415
1.24M
        break;
416
609k
    case UA_NODECLASS_METHOD:
417
609k
        break;
418
906k
    case UA_NODECLASS_OBJECTTYPE:
419
906k
        break;
420
10.3M
    case UA_NODECLASS_VARIABLE:
421
10.7M
    case UA_NODECLASS_VARIABLETYPE: {
422
10.7M
        UA_VariableNode *p = &node->variableNode;
423
10.7M
        UA_NodeId_clear(&p->dataType);
424
10.7M
        UA_Array_delete(p->arrayDimensions, p->arrayDimensionsSize,
425
10.7M
                        &UA_TYPES[UA_TYPES_INT32]);
426
10.7M
        p->arrayDimensions = NULL;
427
10.7M
        p->arrayDimensionsSize = 0;
428
10.7M
        if(p->valueSourceType == UA_VALUESOURCETYPE_INTERNAL)
429
9.67M
            UA_DataValue_clear(&p->valueSource.internal.value);
430
10.7M
        break;
431
10.3M
    }
432
499k
    case UA_NODECLASS_REFERENCETYPE: {
433
499k
        UA_ReferenceTypeNode *p = &node->referenceTypeNode;
434
499k
        UA_LocalizedText_clear(&p->inverseName);
435
499k
        break;
436
10.3M
    }
437
1.20M
    case UA_NODECLASS_DATATYPE:
438
1.20M
        break;
439
1
    case UA_NODECLASS_VIEW:
440
1
        break;
441
0
    default:
442
0
        break;
443
15.2M
    }
444
15.2M
}
445
446
static UA_StatusCode
447
131k
UA_ObjectNode_copy(const UA_ObjectNode *src, UA_ObjectNode *dst) {
448
131k
    dst->eventNotifier = src->eventNotifier;
449
131k
    return UA_STATUSCODE_GOOD;
450
131k
}
451
452
static UA_StatusCode
453
737k
UA_CommonVariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
454
737k
    UA_StatusCode retval =
455
737k
        UA_Array_copy(src->arrayDimensions, src->arrayDimensionsSize,
456
737k
                      (void**)&dst->arrayDimensions, &UA_TYPES[UA_TYPES_INT32]);
457
737k
    if(retval != UA_STATUSCODE_GOOD)
458
0
        return retval;
459
737k
    dst->arrayDimensionsSize = src->arrayDimensionsSize;
460
737k
    retval = UA_NodeId_copy(&src->dataType, &dst->dataType);
461
737k
    dst->valueRank = src->valueRank;
462
737k
    dst->valueSourceType = src->valueSourceType;
463
737k
    dst->valueSource = src->valueSource;
464
737k
    if(src->valueSourceType == UA_VALUESOURCETYPE_INTERNAL)
465
737k
        retval |= UA_DataValue_copy(&src->valueSource.internal.value,
466
737k
                                    &dst->valueSource.internal.value);
467
0
    else if(src->valueSourceType == UA_VALUESOURCETYPE_EXTERNAL)
468
0
        retval |= UA_DataValue_copy(*src->valueSource.external.value,
469
0
                                    &dst->valueSource.internal.value);
470
737k
    return retval;
471
737k
}
472
473
static UA_StatusCode
474
737k
UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
475
737k
    dst->accessLevel = src->accessLevel;
476
737k
    dst->minimumSamplingInterval = src->minimumSamplingInterval;
477
737k
    dst->historizing = src->historizing;
478
737k
    dst->isDynamic = src->isDynamic;
479
737k
    return UA_CommonVariableNode_copy(src, dst);
480
737k
}
481
482
static UA_StatusCode
483
UA_VariableTypeNode_copy(const UA_VariableTypeNode *src,
484
0
                         UA_VariableTypeNode *dst) {
485
0
    dst->isAbstract = src->isAbstract;
486
0
    return UA_CommonVariableNode_copy((const UA_VariableNode*)src, (UA_VariableNode*)dst);
487
0
}
488
489
static UA_StatusCode
490
0
UA_MethodNode_copy(const UA_MethodNode *src, UA_MethodNode *dst) {
491
0
    dst->executable = src->executable;
492
0
    dst->method = src->method;
493
0
    return UA_STATUSCODE_GOOD;
494
0
}
495
496
static UA_StatusCode
497
0
UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectTypeNode *dst) {
498
0
    dst->isAbstract = src->isAbstract;
499
0
    dst->lifecycle = src->lifecycle;
500
0
    return UA_STATUSCODE_GOOD;
501
0
}
502
503
static UA_StatusCode
504
UA_ReferenceTypeNode_copy(const UA_ReferenceTypeNode *src,
505
0
                          UA_ReferenceTypeNode *dst) {
506
0
    dst->isAbstract = src->isAbstract;
507
0
    dst->symmetric = src->symmetric;
508
0
    dst->referenceTypeIndex = src->referenceTypeIndex;
509
0
    dst->subTypes = src->subTypes;
510
0
    return UA_LocalizedText_copy(&src->inverseName, &dst->inverseName);
511
0
}
512
513
static UA_StatusCode
514
0
UA_DataTypeNode_copy(const UA_DataTypeNode *src, UA_DataTypeNode *dst) {
515
0
    dst->isAbstract = src->isAbstract;
516
0
    return UA_STATUSCODE_GOOD;
517
0
}
518
519
static UA_StatusCode
520
0
UA_ViewNode_copy(const UA_ViewNode *src, UA_ViewNode *dst) {
521
0
    dst->containsNoLoops = src->containsNoLoops;
522
0
    dst->eventNotifier = src->eventNotifier;
523
0
    return UA_STATUSCODE_GOOD;
524
0
}
525
526
static void *
527
331k
copyTarget(void *context, UA_ReferenceTargetTreeElem *elm) {
528
331k
    UA_NodeReferenceKind *drefs = (UA_NodeReferenceKind*)context;
529
331k
    return (void*)(uintptr_t)
530
331k
        addReferenceTargetToTree(drefs, elm->target.targetId,
531
331k
                                 elm->targetIdHash,
532
331k
                                 elm->target.targetNameHash);
533
331k
}
534
535
UA_StatusCode
536
869k
UA_Node_copy(const UA_Node *src, UA_Node *dst) {
537
869k
    const UA_NodeHead *srchead = &src->head;
538
869k
    UA_NodeHead *dsthead = &dst->head;
539
869k
    if(srchead->nodeClass != dsthead->nodeClass)
540
0
        return UA_STATUSCODE_BADINTERNALERROR;
541
542
    /* Copy standard content */
543
869k
    UA_StatusCode retval = UA_NodeId_copy(&srchead->nodeId, &dsthead->nodeId);
544
869k
    retval |= UA_QualifiedName_copy(&srchead->browseName, &dsthead->browseName);
545
546
    /* Copy the display name in several languages */
547
1.73M
    for(UA_LocalizedTextListEntry *lt = srchead->displayName; lt != NULL; lt = lt->next) {
548
869k
        UA_LocalizedTextListEntry *newEntry = (UA_LocalizedTextListEntry *)
549
869k
            UA_calloc(1, sizeof(UA_LocalizedTextListEntry));
550
869k
        if(!newEntry) {
551
0
            retval |= UA_STATUSCODE_BADOUTOFMEMORY;
552
0
            break;
553
0
        }
554
869k
        retval |= UA_LocalizedText_copy(&lt->localizedText, &newEntry->localizedText);
555
556
        /* Add to the linked list possibly in reverse order */
557
869k
        newEntry->next = dsthead->displayName;
558
869k
        dsthead->displayName = newEntry;
559
869k
    }
560
561
    /* Copy the description in several languages */
562
869k
    for(UA_LocalizedTextListEntry *lt = srchead->description; lt != NULL; lt = lt->next) {
563
0
        UA_LocalizedTextListEntry *newEntry = (UA_LocalizedTextListEntry *)
564
0
            UA_calloc(1, sizeof(UA_LocalizedTextListEntry));
565
0
        if(!newEntry) {
566
0
            retval |= UA_STATUSCODE_BADOUTOFMEMORY;
567
0
            break;
568
0
        }
569
0
        retval |= UA_LocalizedText_copy(&lt->localizedText, &newEntry->localizedText);
570
571
        /* Add to the linked list possibly in reverse order */
572
0
        newEntry->next = dsthead->description;
573
0
        dsthead->description= newEntry;
574
0
    }
575
576
869k
    dsthead->writeMask = srchead->writeMask;
577
869k
    dsthead->context = srchead->context;
578
869k
    dsthead->constructed = srchead->constructed;
579
869k
#ifdef UA_ENABLE_SUBSCRIPTIONS
580
869k
    dsthead->monitoredItems = srchead->monitoredItems;
581
869k
#endif
582
869k
    if(retval != UA_STATUSCODE_GOOD) {
583
0
        UA_Node_clear(dst);
584
0
        return retval;
585
0
    }
586
587
    /* Copy the references */
588
869k
    dsthead->references = NULL;
589
869k
    dsthead->referencesSize = 0;
590
869k
    if(srchead->referencesSize > 0) {
591
869k
        dsthead->references = (UA_NodeReferenceKind*)
592
869k
            UA_calloc(srchead->referencesSize, sizeof(UA_NodeReferenceKind));
593
869k
        if(!dsthead->references) {
594
0
            UA_Node_clear(dst);
595
0
            return UA_STATUSCODE_BADOUTOFMEMORY;
596
0
        }
597
869k
        dsthead->referencesSize = srchead->referencesSize;
598
599
3.57M
        for(size_t i = 0; i < srchead->referencesSize; ++i) {
600
2.70M
            UA_NodeReferenceKind *srefs = &srchead->references[i];
601
2.70M
            UA_NodeReferenceKind *drefs = &dsthead->references[i];
602
2.70M
            drefs->referenceTypeIndex = srefs->referenceTypeIndex;
603
2.70M
            drefs->isInverse = srefs->isInverse;
604
2.70M
            drefs->hasRefTree = srefs->hasRefTree; /* initially empty */
605
606
            /* Copy all the targets */
607
2.70M
            if(!srefs->hasRefTree) {
608
2.69M
                drefs->targets.array = (UA_ReferenceTarget*)
609
2.69M
                    UA_malloc(sizeof(UA_ReferenceTarget) * srefs->targetsSize);
610
2.69M
                if(!drefs->targets.array) {
611
0
                    UA_Node_clear(dst);
612
0
                    return UA_STATUSCODE_BADOUTOFMEMORY;
613
0
                }
614
5.45M
                for(size_t j = 0; j < srefs->targetsSize; j++) {
615
2.75M
                    drefs->targets.array[j].targetNameHash =
616
2.75M
                        srefs->targets.array[j].targetNameHash;
617
2.75M
                    retval = UA_NodePointer_copy(srefs->targets.array[j].targetId,
618
2.75M
                                                 &drefs->targets.array[j].targetId);
619
2.75M
                    drefs->targetsSize++; /* avoid that targetsSize == 0 in error case */
620
2.75M
                    if(retval != UA_STATUSCODE_GOOD) {
621
0
                        UA_Node_clear(dst);
622
0
                        return retval;
623
0
                    }
624
2.75M
                }
625
2.69M
            } else {
626
7.71k
                void *res = ZIP_ITER(UA_ReferenceIdTree,
627
7.71k
                                     (UA_ReferenceIdTree*)&srefs->targets.tree.idRoot,
628
7.71k
                                     copyTarget, drefs);
629
7.71k
                if(res != NULL) {
630
0
                    UA_Node_clear(dst);
631
0
                    return (UA_StatusCode)(uintptr_t)res;
632
0
                }
633
7.71k
            }
634
635
2.70M
            UA_assert(srefs->targetsSize > 0);
636
2.70M
            UA_assert(srefs->targetsSize == drefs->targetsSize);
637
2.70M
        }
638
869k
    }
639
640
    /* Copy unique content of the nodeclass */
641
869k
    switch(src->head.nodeClass) {
642
131k
    case UA_NODECLASS_OBJECT:
643
131k
        retval = UA_ObjectNode_copy(&src->objectNode, &dst->objectNode);
644
131k
        break;
645
737k
    case UA_NODECLASS_VARIABLE:
646
737k
        retval = UA_VariableNode_copy(&src->variableNode, &dst->variableNode);
647
737k
        break;
648
0
    case UA_NODECLASS_METHOD:
649
0
        retval = UA_MethodNode_copy(&src->methodNode, &dst->methodNode);
650
0
        break;
651
0
    case UA_NODECLASS_OBJECTTYPE:
652
0
        retval = UA_ObjectTypeNode_copy(&src->objectTypeNode, &dst->objectTypeNode);
653
0
        break;
654
0
    case UA_NODECLASS_VARIABLETYPE:
655
0
        retval = UA_VariableTypeNode_copy(&src->variableTypeNode, &dst->variableTypeNode);
656
0
        break;
657
0
    case UA_NODECLASS_REFERENCETYPE:
658
0
        retval = UA_ReferenceTypeNode_copy(&src->referenceTypeNode, &dst->referenceTypeNode);
659
0
        break;
660
0
    case UA_NODECLASS_DATATYPE:
661
0
        retval = UA_DataTypeNode_copy(&src->dataTypeNode, &dst->dataTypeNode);
662
0
        break;
663
0
    case UA_NODECLASS_VIEW:
664
0
        retval = UA_ViewNode_copy(&src->viewNode, &dst->viewNode);
665
0
        break;
666
0
    default:
667
0
        break;
668
869k
    }
669
670
869k
    if(retval != UA_STATUSCODE_GOOD)
671
0
        UA_Node_clear(dst);
672
673
869k
    return retval;
674
869k
}
675
676
UA_Node *
677
0
UA_Node_copy_alloc(const UA_Node *src) {
678
0
    size_t nodesize = 0;
679
0
    switch(src->head.nodeClass) {
680
0
        case UA_NODECLASS_OBJECT:
681
0
            nodesize = sizeof(UA_ObjectNode);
682
0
            break;
683
0
        case UA_NODECLASS_VARIABLE:
684
0
            nodesize = sizeof(UA_VariableNode);
685
0
            break;
686
0
        case UA_NODECLASS_METHOD:
687
0
            nodesize = sizeof(UA_MethodNode);
688
0
            break;
689
0
        case UA_NODECLASS_OBJECTTYPE:
690
0
            nodesize = sizeof(UA_ObjectTypeNode);
691
0
            break;
692
0
        case UA_NODECLASS_VARIABLETYPE:
693
0
            nodesize = sizeof(UA_VariableTypeNode);
694
0
            break;
695
0
        case UA_NODECLASS_REFERENCETYPE:
696
0
            nodesize = sizeof(UA_ReferenceTypeNode);
697
0
            break;
698
0
        case UA_NODECLASS_DATATYPE:
699
0
            nodesize = sizeof(UA_DataTypeNode);
700
0
            break;
701
0
        case UA_NODECLASS_VIEW:
702
0
            nodesize = sizeof(UA_ViewNode);
703
0
            break;
704
0
        default:
705
0
            return NULL;
706
0
    }
707
708
0
    UA_Node *dst = (UA_Node*)UA_calloc(1, nodesize);
709
0
    if(!dst)
710
0
        return NULL;
711
712
0
    dst->head.nodeClass = src->head.nodeClass;
713
714
0
    UA_StatusCode retval = UA_Node_copy(src, dst);
715
0
    if(retval != UA_STATUSCODE_GOOD) {
716
0
        UA_free(dst);
717
0
        return NULL;
718
0
    }
719
0
    return dst;
720
0
}
721
/******************************/
722
/* Copy Attributes into Nodes */
723
/******************************/
724
725
static UA_StatusCode
726
14.3M
copyStandardAttributes(UA_Node *node, const UA_NodeAttributes *attr) {
727
    /* UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId); */
728
    /* UA_QualifiedName_copy(&item->browseName, &node->browseName); */
729
730
14.3M
    node->head.writeMask = attr->writeMask;
731
14.3M
    UA_StatusCode retval = UA_Node_insertOrUpdateDescription(node, &attr->description);
732
    /* The new nodeset format has optional display names:
733
     * https://github.com/open62541/open62541/issues/2627. If the display name
734
     * is NULL, take the name part of the browse name */
735
14.3M
    if(attr->displayName.text.length == 0) {
736
0
        UA_LocalizedText lt;
737
0
        UA_LocalizedText_init(&lt);
738
0
        lt.text = node->head.browseName.name;
739
0
        retval |= UA_Node_insertOrUpdateDisplayName(node, &lt);
740
0
    } else
741
14.3M
        retval |= UA_Node_insertOrUpdateDisplayName(node, &attr->displayName);
742
14.3M
    return retval;
743
14.3M
}
744
745
static UA_StatusCode
746
copyCommonVariableAttributes(UA_VariableNode *node,
747
10.0M
                             const UA_VariableAttributes *attr) {
748
    /* Copy the array dimensions */
749
10.0M
    UA_StatusCode retval =
750
10.0M
        UA_Array_copy(attr->arrayDimensions, attr->arrayDimensionsSize,
751
10.0M
                      (void**)&node->arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]);
752
10.0M
    if(retval != UA_STATUSCODE_GOOD)
753
0
        return retval;
754
10.0M
    node->arrayDimensionsSize = attr->arrayDimensionsSize;
755
756
    /* Data type and value rank */
757
10.0M
    retval = UA_NodeId_copy(&attr->dataType, &node->dataType);
758
10.0M
    if(retval != UA_STATUSCODE_GOOD)
759
0
        return retval;
760
10.0M
    node->valueRank = attr->valueRank;
761
762
    /* Copy the value */
763
10.0M
    node->valueSourceType = UA_VALUESOURCETYPE_INTERNAL;
764
10.0M
    retval = UA_Variant_copy(&attr->value, &node->valueSource.internal.value.value);
765
10.0M
    node->valueSource.internal.value.hasValue =
766
10.0M
        (node->valueSource.internal.value.value.type != NULL);
767
768
10.0M
    return retval;
769
10.0M
}
770
771
static UA_StatusCode
772
copyVariableNodeAttributes(UA_VariableNode *vnode,
773
9.59M
                           const UA_VariableAttributes *attr) {
774
9.59M
    vnode->accessLevel = attr->accessLevel;
775
9.59M
    vnode->historizing = attr->historizing;
776
9.59M
    vnode->minimumSamplingInterval = attr->minimumSamplingInterval;
777
9.59M
    return copyCommonVariableAttributes(vnode, attr);
778
9.59M
}
779
780
static UA_StatusCode
781
copyVariableTypeNodeAttributes(UA_VariableTypeNode *vtnode,
782
428k
                               const UA_VariableTypeAttributes *attr) {
783
428k
    vtnode->isAbstract = attr->isAbstract;
784
428k
    return copyCommonVariableAttributes((UA_VariableNode*)vtnode,
785
428k
                                        (const UA_VariableAttributes*)attr);
786
428k
}
787
788
static UA_StatusCode
789
1.11M
copyObjectNodeAttributes(UA_ObjectNode *onode, const UA_ObjectAttributes *attr) {
790
1.11M
    onode->eventNotifier = attr->eventNotifier;
791
1.11M
    return UA_STATUSCODE_GOOD;
792
1.11M
}
793
794
static UA_StatusCode
795
copyReferenceTypeNodeAttributes(UA_ReferenceTypeNode *rtnode,
796
499k
                                const UA_ReferenceTypeAttributes *attr) {
797
499k
    rtnode->isAbstract = attr->isAbstract;
798
499k
    rtnode->symmetric = attr->symmetric;
799
499k
    return UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName);
800
499k
}
801
802
static UA_StatusCode
803
copyObjectTypeNodeAttributes(UA_ObjectTypeNode *otnode,
804
906k
                             const UA_ObjectTypeAttributes *attr) {
805
906k
    otnode->isAbstract = attr->isAbstract;
806
906k
    return UA_STATUSCODE_GOOD;
807
906k
}
808
809
static UA_StatusCode
810
0
copyViewNodeAttributes(UA_ViewNode *vnode, const UA_ViewAttributes *attr) {
811
0
    vnode->containsNoLoops = attr->containsNoLoops;
812
0
    vnode->eventNotifier = attr->eventNotifier;
813
0
    return UA_STATUSCODE_GOOD;
814
0
}
815
816
static UA_StatusCode
817
copyDataTypeNodeAttributes(UA_DataTypeNode *dtnode,
818
1.20M
                           const UA_DataTypeAttributes *attr) {
819
1.20M
    dtnode->isAbstract = attr->isAbstract;
820
1.20M
    return UA_STATUSCODE_GOOD;
821
1.20M
}
822
823
static UA_StatusCode
824
copyMethodNodeAttributes(UA_MethodNode *mnode,
825
609k
                         const UA_MethodAttributes *attr) {
826
609k
    mnode->executable = attr->executable;
827
609k
    return UA_STATUSCODE_GOOD;
828
609k
}
829
830
14.3M
#define CHECK_ATTRIBUTES(TYPE) do {                     \
831
14.3M
    if(attributeType != &UA_TYPES[UA_TYPES_##TYPE])     \
832
14.3M
        return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;  \
833
14.3M
} while(0)
834
835
UA_StatusCode
836
UA_Node_setAttributes(UA_Node *node, const void *attributes,
837
14.3M
                      const UA_DataType *attributeType) {
838
    /* Copy the attributes into the node */
839
14.3M
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
840
14.3M
    switch(node->head.nodeClass) {
841
1.11M
    case UA_NODECLASS_OBJECT:
842
1.11M
        CHECK_ATTRIBUTES(OBJECTATTRIBUTES);
843
1.11M
        retval = copyObjectNodeAttributes(&node->objectNode,
844
1.11M
                                          (const UA_ObjectAttributes*)attributes);
845
1.11M
        break;
846
9.59M
    case UA_NODECLASS_VARIABLE:
847
9.59M
        CHECK_ATTRIBUTES(VARIABLEATTRIBUTES);
848
9.59M
        retval = copyVariableNodeAttributes(&node->variableNode,
849
9.59M
                                            (const UA_VariableAttributes*)attributes);
850
9.59M
        break;
851
906k
    case UA_NODECLASS_OBJECTTYPE:
852
906k
        CHECK_ATTRIBUTES(OBJECTTYPEATTRIBUTES);
853
906k
        retval = copyObjectTypeNodeAttributes(&node->objectTypeNode,
854
906k
                                              (const UA_ObjectTypeAttributes*)attributes);
855
906k
        break;
856
428k
    case UA_NODECLASS_VARIABLETYPE:
857
428k
        CHECK_ATTRIBUTES(VARIABLETYPEATTRIBUTES);
858
428k
        retval = copyVariableTypeNodeAttributes(&node->variableTypeNode,
859
428k
                                                (const UA_VariableTypeAttributes*)attributes);
860
428k
        break;
861
499k
    case UA_NODECLASS_REFERENCETYPE:
862
499k
        CHECK_ATTRIBUTES(REFERENCETYPEATTRIBUTES);
863
499k
        retval = copyReferenceTypeNodeAttributes(&node->referenceTypeNode,
864
499k
                                                 (const UA_ReferenceTypeAttributes*)attributes);
865
499k
        break;
866
1.20M
    case UA_NODECLASS_DATATYPE:
867
1.20M
        CHECK_ATTRIBUTES(DATATYPEATTRIBUTES);
868
1.20M
        retval = copyDataTypeNodeAttributes(&node->dataTypeNode,
869
1.20M
                                            (const UA_DataTypeAttributes*)attributes);
870
1.20M
        break;
871
1
    case UA_NODECLASS_VIEW:
872
1
        CHECK_ATTRIBUTES(VIEWATTRIBUTES);
873
0
        retval = copyViewNodeAttributes(&node->viewNode, (const UA_ViewAttributes*)attributes);
874
0
        break;
875
609k
    case UA_NODECLASS_METHOD:
876
609k
        CHECK_ATTRIBUTES(METHODATTRIBUTES);
877
609k
        retval = copyMethodNodeAttributes(&node->methodNode, (const UA_MethodAttributes*)attributes);
878
609k
        break;
879
0
    case UA_NODECLASS_UNSPECIFIED:
880
0
    default:
881
0
        retval = UA_STATUSCODE_BADNODECLASSINVALID;
882
14.3M
    }
883
884
    /* No need (and no promise) to call UA_Node_clear in the error case.
885
     * Gets caught and handled outside. */
886
14.3M
    if(UA_LIKELY(retval == UA_STATUSCODE_GOOD))
887
14.3M
        retval = copyStandardAttributes(node, (const UA_NodeAttributes*)attributes);
888
14.3M
    return retval;
889
14.3M
}
890
891
/*********************/
892
/* Manage References */
893
/*********************/
894
895
static UA_StatusCode
896
addReferenceTargetToTree(UA_NodeReferenceKind *rk, UA_NodePointer targetId,
897
24.4M
                         UA_UInt32 targetIdHash, UA_UInt32 targetNameHash) {
898
24.4M
    UA_ReferenceTargetTreeElem *entry = (UA_ReferenceTargetTreeElem*)
899
24.4M
        UA_malloc(sizeof(UA_ReferenceTargetTreeElem));
900
24.4M
    if(!entry)
901
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
902
903
24.4M
    UA_StatusCode res = UA_NodePointer_copy(targetId, &entry->target.targetId);
904
24.4M
    if(res != UA_STATUSCODE_GOOD) {
905
0
        UA_free(entry);
906
0
        return res;
907
0
    }
908
909
24.4M
    entry->targetIdHash = targetIdHash;
910
24.4M
    entry->target.targetNameHash = targetNameHash;
911
912
24.4M
    ZIP_INSERT(UA_ReferenceIdTree,
913
24.4M
               (UA_ReferenceIdTree*)&rk->targets.tree.idRoot, entry);
914
24.4M
    ZIP_INSERT(UA_ReferenceNameTree,
915
24.4M
               (UA_ReferenceNameTree*)&rk->targets.tree.nameRoot, entry);
916
917
24.4M
    rk->targetsSize++;
918
24.4M
    return UA_STATUSCODE_GOOD;
919
24.4M
}
920
921
static UA_StatusCode
922
addReferenceTarget(UA_NodeReferenceKind *rk, UA_NodePointer targetId,
923
76.0M
                   UA_UInt32 targetNameHash) {
924
    /* Insert into tree */
925
76.0M
    if(rk->hasRefTree) {
926
24.0M
        UA_ExpandedNodeId en = UA_NodePointer_toExpandedNodeId(targetId);
927
24.0M
        return addReferenceTargetToTree(rk, targetId, UA_ExpandedNodeId_hash(&en),
928
24.0M
                                        targetNameHash);
929
24.0M
    }
930
931
    /* Insert to the array */
932
51.9M
    UA_ReferenceTarget *newRefs = (UA_ReferenceTarget*)
933
51.9M
        UA_realloc(rk->targets.array,
934
51.9M
                   sizeof(UA_ReferenceTarget) * (rk->targetsSize + 1));
935
51.9M
    if(!newRefs)
936
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
937
51.9M
    rk->targets.array = newRefs;
938
939
51.9M
    UA_StatusCode retval =
940
51.9M
        UA_NodePointer_copy(targetId,
941
51.9M
                            &rk->targets.array[rk->targetsSize].targetId);
942
51.9M
    rk->targets.array[rk->targetsSize].targetNameHash = targetNameHash;
943
51.9M
    if(retval != UA_STATUSCODE_GOOD) {
944
0
        if(rk->targetsSize == 0) {
945
0
            UA_free(rk->targets.array);
946
0
            rk->targets.array = NULL;
947
0
        }
948
0
        return retval;
949
0
    }
950
951
51.9M
    rk->targetsSize++;
952
51.9M
    return UA_STATUSCODE_GOOD;
953
51.9M
}
954
955
static UA_StatusCode
956
addReferenceKind(UA_NodeHead *head, UA_Byte refTypeIndex, UA_Boolean isForward,
957
40.8M
                 const UA_NodePointer target, UA_UInt32 targetBrowseNameHash) {
958
40.8M
    UA_NodeReferenceKind *refs = (UA_NodeReferenceKind*)
959
40.8M
        UA_realloc(head->references,
960
40.8M
                   sizeof(UA_NodeReferenceKind) * (head->referencesSize+1));
961
40.8M
    if(!refs)
962
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
963
40.8M
    head->references = refs;
964
965
40.8M
    UA_NodeReferenceKind *newRef = &refs[head->referencesSize];
966
40.8M
    memset(newRef, 0, sizeof(UA_NodeReferenceKind));
967
40.8M
    newRef->referenceTypeIndex = refTypeIndex;
968
40.8M
    newRef->isInverse = !isForward;
969
40.8M
    UA_StatusCode res = addReferenceTarget(newRef, target, targetBrowseNameHash);
970
40.8M
    if(res != UA_STATUSCODE_GOOD) {
971
0
        if(head->referencesSize == 0) {
972
0
            UA_free(head->references);
973
0
            head->references = NULL;
974
0
        }
975
0
        return res;
976
0
    }
977
978
40.8M
    head->referencesSize++;
979
40.8M
    return UA_STATUSCODE_GOOD;
980
40.8M
}
981
982
UA_StatusCode
983
UA_Node_addReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward,
984
                     const UA_ExpandedNodeId *targetNodeId,
985
72.2M
                     UA_UInt32 targetBrowseNameHash) {
986
    /* Find the matching reference kind */
987
157M
    for(size_t i = 0; i < node->head.referencesSize; ++i) {
988
117M
        UA_NodeReferenceKind *refs = &node->head.references[i];
989
990
        /* Reference direction does not match */
991
117M
        if(refs->isInverse == isForward)
992
53.5M
            continue;
993
994
        /* Reference type does not match */
995
63.4M
        if(refs->referenceTypeIndex != refTypeIndex)
996
32.0M
            continue;
997
998
        /* Does an identical reference already exist? */
999
31.4M
        const UA_ReferenceTarget *found =
1000
31.4M
            UA_NodeReferenceKind_findTarget(refs, targetNodeId);
1001
31.4M
        if(found)
1002
0
            return UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED;
1003
1004
        /* If there are many references, attempt to switch to the
1005
         * tree-representation. This speeds up all reference lookups. Continue
1006
         * with the array-representation in case of an error. */
1007
31.4M
        if(!refs->hasRefTree && refs->targetsSize >= 31)
1008
0
            UA_NodeReferenceKind_switch(refs);
1009
1010
        /* Add to existing ReferenceKind */
1011
31.4M
        return addReferenceTarget(refs, UA_NodePointer_fromExpandedNodeId(targetNodeId),
1012
31.4M
                                  targetBrowseNameHash);
1013
31.4M
    }
1014
1015
    /* Add new ReferenceKind for the target */
1016
40.8M
    return addReferenceKind(&node->head, refTypeIndex, isForward,
1017
40.8M
                            UA_NodePointer_fromExpandedNodeId(targetNodeId),
1018
40.8M
                            targetBrowseNameHash);
1019
1020
72.2M
}
1021
1022
UA_StatusCode
1023
UA_Node_deleteReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward,
1024
1.38M
                        const UA_ExpandedNodeId *targetNodeId) {
1025
1.38M
    UA_NodeHead *head = &node->head;
1026
5.15M
    for(size_t i = 0; i < head->referencesSize; i++) {
1027
4.76M
        UA_NodeReferenceKind *refs = &head->references[i];
1028
4.76M
        if(isForward == refs->isInverse)
1029
1.74M
            continue;
1030
3.02M
        if(refTypeIndex != refs->referenceTypeIndex)
1031
1.63M
            continue;
1032
1033
        /* Cast out the const qualifier (hack!) */
1034
1.38M
        UA_ReferenceTarget *target = (UA_ReferenceTarget*)(uintptr_t)
1035
1.38M
            UA_NodeReferenceKind_findTarget(refs, targetNodeId);
1036
1.38M
        if(!target)
1037
385k
            continue;
1038
1039
        /* Ok, delete the reference. Cannot fail */
1040
1.00M
        refs->targetsSize--;
1041
1042
1.00M
        if(!refs->hasRefTree) {
1043
            /* Remove from array */
1044
202k
            UA_NodePointer_clear(&target->targetId);
1045
1046
            /* Elements remaining. Realloc. */
1047
202k
            if(refs->targetsSize > 0) {
1048
116k
                if(target != &refs->targets.array[refs->targetsSize])
1049
9.42k
                    *target = refs->targets.array[refs->targetsSize];
1050
116k
                UA_ReferenceTarget *newRefs = (UA_ReferenceTarget*)
1051
116k
                    UA_realloc(refs->targets.array,
1052
116k
                               sizeof(UA_ReferenceTarget) * refs->targetsSize);
1053
116k
                if(newRefs)
1054
116k
                    refs->targets.array = newRefs;
1055
116k
                return UA_STATUSCODE_GOOD; /* Realloc allowed to fail */
1056
116k
            }
1057
1058
            /* Remove the last target. Remove the ReferenceKind below */
1059
86.1k
            UA_free(refs->targets.array);
1060
799k
        } else {
1061
799k
            UA_ReferenceTargetTreeElem *elem = (UA_ReferenceTargetTreeElem*)target;
1062
799k
            ZIP_REMOVE(UA_ReferenceIdTree,
1063
799k
                       (UA_ReferenceIdTree*)&refs->targets.tree.idRoot, elem);
1064
799k
            ZIP_REMOVE(UA_ReferenceNameTree,
1065
799k
                       (UA_ReferenceNameTree*)&refs->targets.tree.nameRoot, elem);
1066
799k
            UA_NodePointer_clear(&target->targetId);
1067
799k
            UA_free(target);
1068
799k
            if(refs->targetsSize > 0)
1069
792k
                return UA_STATUSCODE_GOOD;
1070
799k
        }
1071
1072
        /* No targets remaining. Remove the ReferenceKind. */
1073
93.5k
        head->referencesSize--;
1074
93.5k
        if(head->referencesSize > 0) {
1075
            /* No target for the ReferenceType remaining. Remove and shrink down
1076
             * allocated buffer. Ignore errors in case memory buffer could not
1077
             * be shrinked down. */
1078
93.4k
            if(i != head->referencesSize)
1079
22.0k
                head->references[i] = head->references[node->head.referencesSize];
1080
93.4k
            UA_NodeReferenceKind *newRefs = (UA_NodeReferenceKind*)
1081
93.4k
                UA_realloc(head->references,
1082
93.4k
                           sizeof(UA_NodeReferenceKind) * head->referencesSize);
1083
93.4k
            if(newRefs)
1084
93.4k
                head->references = newRefs;
1085
93.4k
        } else {
1086
            /* No remaining references of any ReferenceType */
1087
58
            UA_free(head->references);
1088
58
            head->references = NULL;
1089
58
        }
1090
93.5k
        return UA_STATUSCODE_GOOD;
1091
1.00M
    }
1092
385k
    return UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED;
1093
1.38M
}
1094
1095
void
1096
16.0M
UA_Node_deleteReferencesSubset(UA_Node *node, const UA_ReferenceTypeSet *keepSet) {
1097
16.0M
    UA_NodeHead *head = &node->head;
1098
16.0M
    UA_assert(head->references != NULL || head->referencesSize == 0);
1099
16.0M
    size_t i = 0;
1100
60.3M
    while(i < head->referencesSize) {
1101
        /* Keep the references of this type? */
1102
44.3M
        UA_NodeReferenceKind *refs = &head->references[i];
1103
44.3M
        if(UA_ReferenceTypeSet_contains(keepSet, refs->referenceTypeIndex)){
1104
869k
            i++;
1105
869k
            continue;
1106
869k
        }
1107
1108
        /* Remove all target entries. Don't remove entries from browseName tree.
1109
         * The entire ReferenceKind will be removed anyway. */
1110
43.4M
        if(!refs->hasRefTree) {
1111
93.9M
            for(size_t j = 0; j < refs->targetsSize; j++) {
1112
                /* Consistency requirement: If refs->targetsSize > 0, then the
1113
                 * targets array is non-NULL */
1114
50.7M
                UA_assert(refs->targets.array != NULL);
1115
50.7M
                UA_NodePointer_clear(&refs->targets.array[j].targetId);
1116
50.7M
            }
1117
43.2M
            UA_free(refs->targets.array);
1118
43.2M
        } else {
1119
223k
            ZIP_ITER(UA_ReferenceIdTree,
1120
223k
                     (UA_ReferenceIdTree*)&refs->targets.tree.idRoot,
1121
223k
                     removeTreeEntry, NULL);
1122
223k
        }
1123
1124
        /* Move last references-kind entry to this position. Don't memcpy over
1125
         * the same position. Don't increment i: the swapped-in element must be
1126
         * checked on the next iteration. */
1127
43.4M
        head->referencesSize--;
1128
43.4M
        if(i != head->referencesSize)
1129
27.3M
            head->references[i] = head->references[head->referencesSize];
1130
43.4M
    }
1131
1132
16.0M
    if(head->referencesSize > 0) {
1133
        /* Realloc to save memory. Ignore if realloc fails. */
1134
869k
        UA_NodeReferenceKind *refs = (UA_NodeReferenceKind*)
1135
869k
            UA_realloc(head->references,
1136
869k
                       sizeof(UA_NodeReferenceKind) * head->referencesSize);
1137
869k
        if(refs)
1138
869k
            head->references = refs;
1139
15.2M
    } else {
1140
        /* The array is empty. Remove. */
1141
15.2M
        UA_free(head->references);
1142
15.2M
        head->references = NULL;
1143
15.2M
    }
1144
16.0M
}
1145
1146
15.2M
void UA_Node_deleteReferences(UA_Node *node) {
1147
15.2M
    UA_ReferenceTypeSet noRefs;
1148
15.2M
    UA_ReferenceTypeSet_init(&noRefs);
1149
15.2M
    UA_Node_deleteReferencesSubset(node, &noRefs);
1150
15.2M
}
1151
1152
static UA_StatusCode
1153
UA_Node_insertOrUpdateLocale(UA_LocalizedTextListEntry **root,
1154
28.7M
                             const UA_LocalizedText *value) {
1155
28.7M
    UA_StatusCode res;
1156
28.7M
    UA_LocalizedTextListEntry *lt, *prev = NULL;
1157
28.7M
    for(lt = *root; lt != NULL; prev = lt, lt = lt->next) {
1158
0
        if(!UA_String_equal(&value->locale, &lt->localizedText.locale))
1159
0
            continue;
1160
1161
        /* No text -> remove the entry for this locale */
1162
0
        if(value->text.length == 0) {
1163
0
            if(prev == NULL)
1164
0
                *root = lt->next;
1165
0
            else
1166
0
                prev->next = lt->next;
1167
0
            UA_LocalizedText_clear(&lt->localizedText);
1168
0
            UA_free(lt);
1169
0
            return UA_STATUSCODE_GOOD;
1170
0
        }
1171
1172
        /* First make a copy of the text, if this succeeds replace the old
1173
         * version */
1174
0
        UA_String tmp;
1175
0
        res = UA_String_copy(&value->text, &tmp);
1176
0
        if(res != UA_STATUSCODE_GOOD)
1177
0
            return res;
1178
1179
0
        UA_String_clear(&lt->localizedText.text);
1180
0
        lt->localizedText.text = tmp;
1181
0
        return UA_STATUSCODE_GOOD;
1182
0
    }
1183
1184
    /* The locale does not exist so far */
1185
1186
    /* Do nothing if a non-existing locale should be removed */
1187
28.7M
    if(value->text.length == 0)
1188
14.1M
        return UA_STATUSCODE_GOOD;
1189
1190
    /* Add a new localized text */
1191
14.5M
    lt = (UA_LocalizedTextListEntry *)UA_malloc(sizeof(UA_LocalizedTextListEntry));
1192
14.5M
    if(!lt)
1193
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
1194
1195
14.5M
    res = UA_LocalizedText_copy(value, &lt->localizedText);
1196
14.5M
    if(res != UA_STATUSCODE_GOOD) {
1197
0
        UA_free(lt);
1198
0
        return res;
1199
0
    }
1200
1201
14.5M
    lt->next = *root;
1202
14.5M
    *root = lt;
1203
14.5M
    return UA_STATUSCODE_GOOD;
1204
14.5M
}
1205
1206
UA_StatusCode
1207
UA_Node_insertOrUpdateDisplayName(UA_Node *node,
1208
14.3M
                                  const UA_LocalizedText *displayName) {
1209
14.3M
    return UA_Node_insertOrUpdateLocale(&node->head.displayName, displayName);
1210
14.3M
}
1211
1212
UA_StatusCode
1213
UA_Node_insertOrUpdateDescription(UA_Node *node,
1214
14.3M
                                  const UA_LocalizedText *description) {
1215
14.3M
    return UA_Node_insertOrUpdateLocale(&node->head.description, description);
1216
14.3M
}