Browse Source

return partial content of a range (fix #1055)

Julius Pfrommer 6 years ago
parent
commit
089dd7aae8
2 changed files with 39 additions and 8 deletions
  1. 11 0
      CHANGELOG
  2. 28 8
      src/ua_types.c

+ 11 - 0
CHANGELOG

@@ -1,6 +1,17 @@
 The changelog tracks changes to the public API.
 Internal refactorings and bug fixes are not reported here.
 
+2017-07-04 jpfr <julius.pfrommer at web.de>
+
+    * Return partially overlapping ranges
+
+      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 speify a range that is within
+      the bounds of the array. The Server shall return a partial result if some
+      elements exist within the range.
+
 2017-05-03 pro <profanter at fortiss.org>
 
     * Array dimensions are UInt32 also for the highlevel client read service

+ 28 - 8
src/ua_types.c

@@ -464,7 +464,7 @@ computeStrides(const UA_Variant *v, const UA_NumericRange range,
 #endif
 
     /* Test the integrity of the source variant dimensions, make dimensions
-       vector of one dimension if none defined */
+     * vector of one dimension if none defined */
     UA_UInt32 arrayLength = (UA_UInt32)v->arrayLength;
     const UA_UInt32 *dims = &arrayLength;
     size_t dims_count = 1;
@@ -477,18 +477,32 @@ computeStrides(const UA_Variant *v, const UA_NumericRange range,
         if(elements != v->arrayLength)
             return UA_STATUSCODE_BADINTERNALERROR;
     }
-
-    /* Test the integrity of the range */
+    UA_assert(dims_count > 0);
+
+    /* 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. */
     size_t count = 1;
+    UA_UInt32 *realmax = UA_alloca(sizeof(UA_UInt32) * dims_count);
     if(range.dimensionsSize != dims_count)
         return UA_STATUSCODE_BADINDEXRANGENODATA;
     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].max >= dims[i])
+        if(range.dimensions[i].min >= dims[i])
             return UA_STATUSCODE_BADINDEXRANGENODATA;
-        count *= (range.dimensions[i].max - range.dimensions[i].min) + 1;
+
+        if(range.dimensions[i].max < dims[i])
+            realmax[i] = range.dimensions[i].max;
+        else
+            realmax[i] = dims[i] - 1;
+
+        count *= (realmax[i] - range.dimensions[i].min) + 1;
     }
+
     *total = count;
 
     /* Compute the stride length and the position of the first element */
@@ -499,7 +513,7 @@ computeStrides(const UA_Variant *v, const UA_NumericRange range,
     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;
+        size_t dimrange = 1 + realmax[k] - range.dimensions[k].min;
         if(!found_contiguous && dimrange != dims[k]) {
             /* Found the maximum block that can be copied contiguously */
             found_contiguous = true;
@@ -522,15 +536,21 @@ isStringLike(const UA_DataType *type) {
     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->max >= src->length)
+    if(dim->min >= src->length)
         return UA_STATUSCODE_BADINDEXRANGENODATA;
 
-    size_t length = dim->max - dim->min + 1;
+    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;