|
@@ -419,12 +419,74 @@ UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint,
|
|
/* TranslateBrowsePath */
|
|
/* TranslateBrowsePath */
|
|
/***********************/
|
|
/***********************/
|
|
|
|
|
|
-static UA_StatusCode
|
|
|
|
-walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, const UA_RelativePath *path,
|
|
|
|
- size_t pathindex, UA_BrowsePathTarget **targets, size_t *targets_size,
|
|
|
|
- size_t *target_count) {
|
|
|
|
- const UA_RelativePathElement *elem = &path->elements[pathindex];
|
|
|
|
- UA_StatusCode retval = UA_STATUSCODE_GOOD;
|
|
|
|
|
|
+static void
|
|
|
|
+walkBrowsePathElementNode(UA_BrowsePathResult *result, size_t *targetsSize,
|
|
|
|
+ UA_NodeId **next, size_t *nextSize, size_t *nextCount,
|
|
|
|
+ UA_UInt32 elemDepth, UA_Boolean inverse, UA_Boolean all_refs,
|
|
|
|
+ const UA_NodeId *reftypes, size_t reftypes_count, const UA_Node *node) {
|
|
|
|
+ /* Loop over the nodes references */
|
|
|
|
+ for(size_t i = 0; i < node->referencesSize &&
|
|
|
|
+ result->statusCode == UA_STATUSCODE_GOOD; i++) {
|
|
|
|
+ UA_ReferenceNode *reference = &node->references[i];
|
|
|
|
+
|
|
|
|
+ /* Does the direction of the reference match? */
|
|
|
|
+ if(reference->isInverse != inverse)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ /* Is the node relevant? */
|
|
|
|
+ if(!all_refs) {
|
|
|
|
+ UA_Boolean match = false;
|
|
|
|
+ for(size_t j = 0; j < reftypes_count; ++j) {
|
|
|
|
+ if(UA_NodeId_equal(&reference->referenceTypeId, &reftypes[j])) {
|
|
|
|
+ match = true;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if(!match)
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Does the reference point to an external server? Then add to the
|
|
|
|
+ targets with the right path "depth" */
|
|
|
|
+ if(reference->targetId.serverIndex != 0) {
|
|
|
|
+ UA_BrowsePathTarget *tempTargets =
|
|
|
|
+ UA_realloc(result->targets, sizeof(UA_BrowsePathTarget) * (*targetsSize) * 2);
|
|
|
|
+ if(!tempTargets) {
|
|
|
|
+ result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ result->targets = tempTargets;
|
|
|
|
+ (*targetsSize) *= 2;
|
|
|
|
+ result->statusCode = UA_ExpandedNodeId_copy(&reference->targetId,
|
|
|
|
+ &result->targets[result->targetsSize].targetId);
|
|
|
|
+ result->targets[result->targetsSize].remainingPathIndex = elemDepth;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Add the node to the next array for the following path element */
|
|
|
|
+ if(*nextSize <= *nextCount) {
|
|
|
|
+ UA_NodeId *tempNext = UA_realloc(*next, sizeof(UA_NodeId) * (*nextSize) * 2);
|
|
|
|
+ if(!tempNext) {
|
|
|
|
+ result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ *next = tempNext;
|
|
|
|
+ (*nextSize) *= 2;
|
|
|
|
+ }
|
|
|
|
+ result->statusCode = UA_NodeId_copy(&reference->targetId.nodeId,
|
|
|
|
+ &(*next)[*nextCount]);
|
|
|
|
+ ++(*nextCount);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+walkBrowsePathElement(UA_Server *server, UA_Session *session,
|
|
|
|
+ UA_BrowsePathResult *result, size_t *targetsSize,
|
|
|
|
+ const UA_RelativePathElement *elem, UA_UInt32 elemDepth,
|
|
|
|
+ const UA_QualifiedName *targetName,
|
|
|
|
+ const UA_NodeId *current, const size_t currentCount,
|
|
|
|
+ UA_NodeId **next, size_t *nextSize, size_t *nextCount) {
|
|
|
|
+ /* Get the full list of relevant referencetypes for this path element */
|
|
UA_NodeId *reftypes = NULL;
|
|
UA_NodeId *reftypes = NULL;
|
|
size_t reftypes_count = 1; // all_refs or no subtypes => 1
|
|
size_t reftypes_count = 1; // all_refs or no subtypes => 1
|
|
UA_Boolean all_refs = false;
|
|
UA_Boolean all_refs = false;
|
|
@@ -435,104 +497,208 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
|
|
} else {
|
|
} else {
|
|
const UA_Node *rootRef = UA_NodeStore_get(server->nodestore, &elem->referenceTypeId);
|
|
const UA_Node *rootRef = UA_NodeStore_get(server->nodestore, &elem->referenceTypeId);
|
|
if(!rootRef || rootRef->nodeClass != UA_NODECLASS_REFERENCETYPE)
|
|
if(!rootRef || rootRef->nodeClass != UA_NODECLASS_REFERENCETYPE)
|
|
- return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
|
|
|
|
- retval = getTypeHierarchy(server->nodestore, rootRef, false, &reftypes, &reftypes_count);
|
|
|
|
|
|
+ return;
|
|
|
|
+ UA_StatusCode retval =
|
|
|
|
+ getTypeHierarchy(server->nodestore, rootRef, false, &reftypes, &reftypes_count);
|
|
if(retval != UA_STATUSCODE_GOOD)
|
|
if(retval != UA_STATUSCODE_GOOD)
|
|
- return retval;
|
|
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- for(size_t i = 0; i < node->referencesSize && retval == UA_STATUSCODE_GOOD; ++i) {
|
|
|
|
- UA_Boolean match = all_refs;
|
|
|
|
- for(size_t j = 0; j < reftypes_count && !match; ++j) {
|
|
|
|
- if(node->references[i].isInverse == elem->isInverse &&
|
|
|
|
- UA_NodeId_equal(&node->references[i].referenceTypeId, &reftypes[j]))
|
|
|
|
- match = true;
|
|
|
|
|
|
+ /* Iterate over all nodes at the current depth-level */
|
|
|
|
+ for(size_t i = 0; i < currentCount; ++i) {
|
|
|
|
+ /* Get the node */
|
|
|
|
+ const UA_Node *node = UA_NodeStore_get(server->nodestore, ¤t[i]);
|
|
|
|
+ if(!node) {
|
|
|
|
+ /* If we cannot find the node at depth 0, the starting node does not exist */
|
|
|
|
+ if(elemDepth == 0)
|
|
|
|
+ result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
|
|
|
|
+ continue;
|
|
}
|
|
}
|
|
- if(!match)
|
|
|
|
|
|
+
|
|
|
|
+ /* Test whether the current node has the target name required in the
|
|
|
|
+ * previous path element */
|
|
|
|
+ if(targetName && (targetName->namespaceIndex != node->browseName.namespaceIndex ||
|
|
|
|
+ !UA_String_equal(&targetName->name, &node->browseName.name)))
|
|
continue;
|
|
continue;
|
|
|
|
|
|
- // get the node, todo: expandednodeid
|
|
|
|
- const UA_Node *next = UA_NodeStore_get(server->nodestore, &node->references[i].targetId.nodeId);
|
|
|
|
- if(!next)
|
|
|
|
|
|
+ /* Walk over the references in the node */
|
|
|
|
+ walkBrowsePathElementNode(result, targetsSize, next, nextSize, nextCount, elemDepth,
|
|
|
|
+ elem->isInverse, all_refs, reftypes, reftypes_count, node);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(!all_refs && elem->includeSubtypes)
|
|
|
|
+ UA_Array_delete(reftypes, reftypes_count, &UA_TYPES[UA_TYPES_NODEID]);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* This assumes that result->targets has enough room for all currentCount elements */
|
|
|
|
+static void
|
|
|
|
+addBrowsePathTargets(UA_Server *server, UA_Session *session, UA_BrowsePathResult *result,
|
|
|
|
+ const UA_QualifiedName *targetName, UA_NodeId *current, size_t currentCount) {
|
|
|
|
+ for(size_t i = 0; i < currentCount; i++) {
|
|
|
|
+ /* Get the node */
|
|
|
|
+ const UA_Node *node = UA_NodeStore_get(server->nodestore, ¤t[i]);
|
|
|
|
+ if(!node) {
|
|
|
|
+ UA_NodeId_deleteMembers(¤t[i]);
|
|
continue;
|
|
continue;
|
|
|
|
+ }
|
|
|
|
|
|
- // test the browsename
|
|
|
|
- if(elem->targetName.namespaceIndex != next->browseName.namespaceIndex ||
|
|
|
|
- !UA_String_equal(&elem->targetName.name, &next->browseName.name)) {
|
|
|
|
|
|
+ /* Test whether the current node has the target name required in the
|
|
|
|
+ * previous path element */
|
|
|
|
+ if(targetName->namespaceIndex != node->browseName.namespaceIndex ||
|
|
|
|
+ !UA_String_equal(&targetName->name, &node->browseName.name)) {
|
|
|
|
+ UA_NodeId_deleteMembers(¤t[i]);
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
- if(pathindex + 1 < path->elementsSize) {
|
|
|
|
- // recursion if the path is longer
|
|
|
|
- retval = walkBrowsePath(server, session, next, path, pathindex + 1,
|
|
|
|
- targets, targets_size, target_count);
|
|
|
|
- } else {
|
|
|
|
- // add the browsetarget
|
|
|
|
- if(*target_count >= *targets_size) {
|
|
|
|
- UA_BrowsePathTarget *newtargets;
|
|
|
|
- newtargets = UA_realloc(targets, sizeof(UA_BrowsePathTarget) * (*targets_size) * 2);
|
|
|
|
- if(!newtargets) {
|
|
|
|
- retval = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- *targets = newtargets;
|
|
|
|
- *targets_size *= 2;
|
|
|
|
- }
|
|
|
|
|
|
+ /* Move the nodeid to the target array */
|
|
|
|
+ UA_BrowsePathTarget_init(&result->targets[result->targetsSize]);
|
|
|
|
+ result->targets[result->targetsSize].targetId.nodeId = current[i];
|
|
|
|
+ result->targets[result->targetsSize].remainingPathIndex = UA_UINT32_MAX;
|
|
|
|
+ ++result->targetsSize;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- UA_BrowsePathTarget *res = *targets;
|
|
|
|
- UA_ExpandedNodeId_init(&res[*target_count].targetId);
|
|
|
|
- retval = UA_NodeId_copy(&next->nodeId, &res[*target_count].targetId.nodeId);
|
|
|
|
- if(retval != UA_STATUSCODE_GOOD)
|
|
|
|
- break;
|
|
|
|
- res[*target_count].remainingPathIndex = UA_UINT32_MAX;
|
|
|
|
- *target_count += 1;
|
|
|
|
|
|
+static void
|
|
|
|
+walkBrowsePath(UA_Server *server, UA_Session *session, const UA_BrowsePath *path,
|
|
|
|
+ UA_BrowsePathResult *result, size_t targetsSize,
|
|
|
|
+ UA_NodeId **current, size_t *currentSize, size_t *currentCount,
|
|
|
|
+ UA_NodeId **next, size_t *nextSize, size_t *nextCount) {
|
|
|
|
+ UA_assert(*currentCount == 1);
|
|
|
|
+ UA_assert(*nextCount == 0);
|
|
|
|
+
|
|
|
|
+ /* Points to the targetName of the _previous_ path element */
|
|
|
|
+ const UA_QualifiedName *targetName = NULL;
|
|
|
|
+
|
|
|
|
+ /* Iterate over path elements */
|
|
|
|
+ UA_assert(path->relativePath.elementsSize > 0);
|
|
|
|
+ for(UA_UInt32 i = 0; i < path->relativePath.elementsSize; ++i) {
|
|
|
|
+ walkBrowsePathElement(server, session, result, &targetsSize,
|
|
|
|
+ &path->relativePath.elements[i], i, targetName,
|
|
|
|
+ *current, *currentCount, next, nextSize, nextCount);
|
|
|
|
+
|
|
|
|
+ /* Clean members of current */
|
|
|
|
+ for(size_t j = 0; j < *currentCount; j++)
|
|
|
|
+ UA_NodeId_deleteMembers(&(*current)[j]);
|
|
|
|
+ *currentCount = 0;
|
|
|
|
+
|
|
|
|
+ /* When no targets are left or an error occurred. None of next's
|
|
|
|
+ * elements will be copied to result->targets */
|
|
|
|
+ if(nextCount == 0 || result->statusCode != UA_STATUSCODE_GOOD) {
|
|
|
|
+ UA_assert(*currentCount == 0);
|
|
|
|
+ UA_assert(*nextCount == 0);
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /* Exchange current and next for the next depth */
|
|
|
|
+ size_t tSize = *currentSize; size_t tCount = *currentCount; UA_NodeId *tT = *current;
|
|
|
|
+ *currentSize = *nextSize; *currentCount = *nextCount; *current = *next;
|
|
|
|
+ *nextSize = tSize; *nextCount = tCount; *next = tT;
|
|
|
|
+
|
|
|
|
+ /* Store the target name of the previous path element */
|
|
|
|
+ targetName = &path->relativePath.elements[i].targetName;
|
|
}
|
|
}
|
|
|
|
|
|
- if(!all_refs && elem->includeSubtypes)
|
|
|
|
- UA_Array_delete(reftypes, reftypes_count, &UA_TYPES[UA_TYPES_NODEID]);
|
|
|
|
- return retval;
|
|
|
|
|
|
+ UA_assert(targetName != NULL);
|
|
|
|
+ UA_assert(*nextCount == 0);
|
|
|
|
+
|
|
|
|
+ /* After the last BrowsePathElement, move members from current to the
|
|
|
|
+ * result targets */
|
|
|
|
+
|
|
|
|
+ /* Realloc if more space is needed */
|
|
|
|
+ if(targetsSize < result->targetsSize + (*currentCount)) {
|
|
|
|
+ UA_BrowsePathTarget *newTargets =
|
|
|
|
+ (UA_BrowsePathTarget*)UA_realloc(result->targets, sizeof(UA_BrowsePathTarget) *
|
|
|
|
+ (result->targetsSize + (*currentCount)));
|
|
|
|
+ if(!newTargets) {
|
|
|
|
+ result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
|
+ for(size_t i = 0; i < *currentCount; ++i)
|
|
|
|
+ UA_NodeId_deleteMembers(&(*current)[i]);
|
|
|
|
+ *currentCount = 0;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ result->targets = newTargets;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Move the elements of current to the targets */
|
|
|
|
+ addBrowsePathTargets(server, session, result, targetName, *current, *currentCount);
|
|
|
|
+ *currentCount = 0;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
-translateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
|
|
|
|
- const UA_BrowsePath *path, UA_BrowsePathResult *result) {
|
|
|
|
|
|
+translateBrowsePathToNodeIds(UA_Server *server, UA_Session *session,
|
|
|
|
+ const UA_BrowsePath *path, UA_BrowsePathResult *result) {
|
|
if(path->relativePath.elementsSize <= 0) {
|
|
if(path->relativePath.elementsSize <= 0) {
|
|
result->statusCode = UA_STATUSCODE_BADNOTHINGTODO;
|
|
result->statusCode = UA_STATUSCODE_BADNOTHINGTODO;
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- //relativePath elements should not have an empty targetName
|
|
|
|
- for(size_t i=0;i<path->relativePath.elementsSize;++i){
|
|
|
|
- UA_QualifiedName *qname = &(path->relativePath.elements[i].targetName);
|
|
|
|
- if(UA_QualifiedName_isNull(qname)){
|
|
|
|
|
|
+ /* 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;
|
|
result->statusCode = UA_STATUSCODE_BADBROWSENAMEINVALID;
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- size_t arraySize = 10;
|
|
|
|
- result->targets = UA_malloc(sizeof(UA_BrowsePathTarget) * arraySize);
|
|
|
|
|
|
+ /* Allocate memory for the targets */
|
|
|
|
+ size_t targetsSize = 10; /* When to realloc; the member count is stored in
|
|
|
|
+ * result->targetsSize */
|
|
|
|
+ result->targets = (UA_BrowsePathTarget*)UA_malloc(sizeof(UA_BrowsePathTarget) * targetsSize);
|
|
if(!result->targets) {
|
|
if(!result->targets) {
|
|
result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- result->targetsSize = 0;
|
|
|
|
- const UA_Node *firstNode = UA_NodeStore_get(server->nodestore, &path->startingNode);
|
|
|
|
- if(!firstNode) {
|
|
|
|
- result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
|
|
|
|
|
|
+
|
|
|
|
+ /* Allocate memory for two temporary arrays. One with the results for the
|
|
|
|
+ * previous depth of the path. The other for the new results at the current
|
|
|
|
+ * depth. The two arrays alternate as we descend down the tree. */
|
|
|
|
+ size_t currentSize = 10; /* When to realloc */
|
|
|
|
+ size_t currentCount = 0; /* Current elements */
|
|
|
|
+ UA_NodeId *current = (UA_NodeId*)UA_malloc(sizeof(UA_NodeId) * currentSize);
|
|
|
|
+ if(!current) {
|
|
|
|
+ result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
UA_free(result->targets);
|
|
UA_free(result->targets);
|
|
- result->targets = NULL;
|
|
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
+ size_t nextSize = 10; /* When to realloc */
|
|
|
|
+ size_t nextCount = 0; /* Current elements */
|
|
|
|
+ UA_NodeId *next = (UA_NodeId*)UA_malloc(sizeof(UA_NodeId) * nextSize);
|
|
|
|
+ if(!next) {
|
|
|
|
+ result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
|
+ UA_free(result->targets);
|
|
|
|
+ UA_free(current);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Copy the starting node into current */
|
|
|
|
+ result->statusCode = UA_NodeId_copy(&path->startingNode, ¤t[0]);
|
|
|
|
+ if(result->statusCode != UA_STATUSCODE_GOOD) {
|
|
|
|
+ UA_free(result->targets);
|
|
|
|
+ UA_free(current);
|
|
|
|
+ UA_free(next);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ currentCount = 1;
|
|
|
|
+
|
|
|
|
+ /* Walk the path elements */
|
|
|
|
+ walkBrowsePath(server, session, path, result, targetsSize,
|
|
|
|
+ ¤t, ¤tSize, ¤tCount,
|
|
|
|
+ &next, &nextSize, &nextCount);
|
|
|
|
+
|
|
|
|
+ UA_assert(currentCount == 0);
|
|
|
|
+ UA_assert(nextCount == 0);
|
|
|
|
|
|
- result->statusCode = walkBrowsePath(server, session, firstNode, &path->relativePath, 0,
|
|
|
|
- &result->targets, &arraySize, &result->targetsSize);
|
|
|
|
|
|
+ /* No results => BadNoMatch status code */
|
|
if(result->targetsSize == 0 && result->statusCode == UA_STATUSCODE_GOOD)
|
|
if(result->targetsSize == 0 && result->statusCode == UA_STATUSCODE_GOOD)
|
|
result->statusCode = UA_STATUSCODE_BADNOMATCH;
|
|
result->statusCode = UA_STATUSCODE_BADNOMATCH;
|
|
|
|
|
|
|
|
+ /* Clean up the temporary arrays and the targets */
|
|
|
|
+ UA_free(current);
|
|
|
|
+ UA_free(next);
|
|
if(result->statusCode != UA_STATUSCODE_GOOD) {
|
|
if(result->statusCode != UA_STATUSCODE_GOOD) {
|
|
- UA_Array_delete(result->targets, result->targetsSize, &UA_TYPES[UA_TYPES_BROWSEPATHTARGET]);
|
|
|
|
|
|
+ for(size_t i = 0; i < result->targetsSize; ++i)
|
|
|
|
+ UA_BrowsePathTarget_deleteMembers(&result->targets[i]);
|
|
|
|
+ UA_free(result->targets);
|
|
result->targets = NULL;
|
|
result->targets = NULL;
|
|
result->targetsSize = 0;
|
|
result->targetsSize = 0;
|
|
}
|
|
}
|
|
@@ -544,7 +710,7 @@ UA_Server_translateBrowsePathToNodeIds(UA_Server *server,
|
|
UA_BrowsePathResult result;
|
|
UA_BrowsePathResult result;
|
|
UA_BrowsePathResult_init(&result);
|
|
UA_BrowsePathResult_init(&result);
|
|
UA_RCU_LOCK();
|
|
UA_RCU_LOCK();
|
|
- translateBrowsePathsToNodeIds(server, &adminSession, browsePath, &result);
|
|
|
|
|
|
+ translateBrowsePathToNodeIds(server, &adminSession, browsePath, &result);
|
|
UA_RCU_UNLOCK();
|
|
UA_RCU_UNLOCK();
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
@@ -590,16 +756,18 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
|
|
indices, (UA_UInt32)indexSize, response->results,
|
|
indices, (UA_UInt32)indexSize, response->results,
|
|
response->diagnosticInfos);
|
|
response->diagnosticInfos);
|
|
}
|
|
}
|
|
-#endif
|
|
|
|
-
|
|
|
|
response->resultsSize = size;
|
|
response->resultsSize = size;
|
|
for(size_t i = 0; i < size; ++i) {
|
|
for(size_t i = 0; i < size; ++i) {
|
|
-#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
|
|
|
|
if(!isExternal[i])
|
|
if(!isExternal[i])
|
|
-#endif
|
|
|
|
- translateBrowsePathsToNodeIds(server, session, &request->browsePaths[i],
|
|
|
|
- &response->results[i]);
|
|
|
|
|
|
+ translateBrowsePathToNodeIds(server, session, &request->browsePaths[i],
|
|
|
|
+ &response->results[i]);
|
|
}
|
|
}
|
|
|
|
+#else
|
|
|
|
+ response->resultsSize = size;
|
|
|
|
+ for(size_t i = 0; i < size; ++i)
|
|
|
|
+ translateBrowsePathToNodeIds(server, session, &request->browsePaths[i],
|
|
|
|
+ &response->results[i]);
|
|
|
|
+#endif
|
|
}
|
|
}
|
|
|
|
|
|
void Service_RegisterNodes(UA_Server *server, UA_Session *session, const UA_RegisterNodesRequest *request,
|
|
void Service_RegisterNodes(UA_Server *server, UA_Session *session, const UA_RegisterNodesRequest *request,
|