Browse Source

return partial content of a range (fix #1055)

Julius Pfrommer 7 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.
 The changelog tracks changes to the public API.
 Internal refactorings and bug fixes are not reported here.
 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>
 2017-05-03 pro <profanter at fortiss.org>
 
 
     * Array dimensions are UInt32 also for the highlevel client read service
     * 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
 #endif
 
 
     /* Test the integrity of the source variant dimensions, make dimensions
     /* 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;
     UA_UInt32 arrayLength = (UA_UInt32)v->arrayLength;
     const UA_UInt32 *dims = &arrayLength;
     const UA_UInt32 *dims = &arrayLength;
     size_t dims_count = 1;
     size_t dims_count = 1;
@@ -477,18 +477,32 @@ computeStrides(const UA_Variant *v, const UA_NumericRange range,
         if(elements != v->arrayLength)
         if(elements != v->arrayLength)
             return UA_STATUSCODE_BADINTERNALERROR;
             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;
     size_t count = 1;
+    UA_UInt32 *realmax = UA_alloca(sizeof(UA_UInt32) * dims_count);
     if(range.dimensionsSize != dims_count)
     if(range.dimensionsSize != dims_count)
         return UA_STATUSCODE_BADINDEXRANGENODATA;
         return UA_STATUSCODE_BADINDEXRANGENODATA;
     for(size_t i = 0; i < dims_count; ++i) {
     for(size_t i = 0; i < dims_count; ++i) {
         if(range.dimensions[i].min > range.dimensions[i].max)
         if(range.dimensions[i].min > range.dimensions[i].max)
             return UA_STATUSCODE_BADINDEXRANGEINVALID;
             return UA_STATUSCODE_BADINDEXRANGEINVALID;
-        if(range.dimensions[i].max >= dims[i])
+        if(range.dimensions[i].min >= dims[i])
             return UA_STATUSCODE_BADINDEXRANGENODATA;
             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;
     *total = count;
 
 
     /* Compute the stride length and the position of the first element */
     /* 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;
     UA_Boolean found_contiguous = false;
     for(size_t k = dims_count; k > 0;) {
     for(size_t k = dims_count; k > 0;) {
         --k;
         --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]) {
         if(!found_contiguous && dimrange != dims[k]) {
             /* Found the maximum block that can be copied contiguously */
             /* Found the maximum block that can be copied contiguously */
             found_contiguous = true;
             found_contiguous = true;
@@ -522,15 +536,21 @@ isStringLike(const UA_DataType *type) {
     return false;
     return false;
 }
 }
 
 
+/* Returns the part of the string that lies within the rangedimension */
 static UA_StatusCode
 static UA_StatusCode
 copySubString(const UA_String *src, UA_String *dst,
 copySubString(const UA_String *src, UA_String *dst,
               const UA_NumericRangeDimension *dim) {
               const UA_NumericRangeDimension *dim) {
     if(dim->min > dim->max)
     if(dim->min > dim->max)
         return UA_STATUSCODE_BADINDEXRANGEINVALID;
         return UA_STATUSCODE_BADINDEXRANGEINVALID;
-    if(dim->max >= src->length)
+    if(dim->min >= src->length)
         return UA_STATUSCODE_BADINDEXRANGENODATA;
         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);
     UA_StatusCode retval = UA_ByteString_allocBuffer(dst, length);
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
         return retval;