This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 8ae43dd0ce149da6e0d598dc9e79b5d8de699230
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sun Mar 21 21:26:54 2021 +0100

    Fix an `ArrayIndexoutOfBoundsException` in 
`WKTUtilities.cornersAndCenter(…)`
    when the grid size is smaller than `2*cornerSize + 1`.
---
 .../sis/internal/referencing/WKTUtilities.java     | 28 ++++++++++++++++++----
 .../main/java/org/apache/sis/io/wkt/Formatter.java | 20 ++++++++--------
 2 files changed, 33 insertions(+), 15 deletions(-)

diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java
index 89ac500..5a8e0ce 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java
@@ -432,7 +432,13 @@ public final class WKTUtilities extends Static {
      * Returns the values in the corners and in the center of the given 
tensor. The values are returned in a
      * <var>n</var>-dimensional array of {@link Number} where <var>n</var> is 
the length of {@code size}.
      * If some values have been skipped, {@code null} values are inserted in 
the rows or columns where the
-     * skipping occurs.
+     * skipping occurs. Caller may replace null values by {@code "…"} string 
at formatting time for example.
+     *
+     * <p>Indices of elements in the returned array are in reverse order than 
in the {@code size} argument.
+     * For example if {@code size} contains the values for dimensions (x,y,z) 
in that order, then elements
+     * in the returned array are accessed with {@code 
cornersAndCenter[z][y][x]} indices in that order.
+     * It is done that way because in the common case where there is only two 
dimensions,
+     * {@code cornersAndCenter[y]} is a row. This is what WKT formatter 
expects among others.</p>
      *
      * @param  tensor      function providing values of the tensor. Inputs are 
indices of the desired value with
      *                     index in each dimension ranging from 0 inclusive to 
{@code size[dimension]} exclusive.
@@ -444,7 +450,7 @@ public final class WKTUtilities extends Static {
      */
     public static Object[] cornersAndCenter(final Function<int[],Number> 
tensor, final int[] size, final int cornerSize) {
         /*
-         * The 'source' array will contain indices of values to fetch in the 
tensor, and the 'target' array will contain
+         * The `source` array will contain indices of values to fetch in the 
tensor, and the `target` array will contain
          * indices where to store those values in the returned data structure. 
Other arrays contain threshold indices of
          * points of interest in the target data structure.
          */
@@ -459,11 +465,18 @@ public final class WKTUtilities extends Static {
         }
         final int[] source = new int[shown.length];
         final int[] target = new int[shown.length];
-        final Object[] numbers = (Object[]) Array.newInstance(Number.class, 
shown);
+        final Object[] numbers;
+        {
+            final int[] reversed = new int[shown.length];
+            for (int i=0; i<reversed.length;) {
+                reversed[i] = shown[shown.length - ++i];
+            }
+            numbers = (Object[]) Array.newInstance(Number.class, reversed);
+        }
         /*
          * The loops below are used for simulating GOTO statements. This is 
usually a deprecated practice,
          * but in this case we can hardly use normal loops because the number 
of nested loops is dynamic.
-         * We want something equivalent to the code below where 'n' - the 
number of nested loops - is not
+         * We want something equivalent to the code below where `n` - the 
number of nested loops - is not
          * known at compile-time:
          *
          * for (int i0=0; i0<size[0]; i0++) {
@@ -516,10 +529,15 @@ fill:   for (;;) {
         Object walk = numbers;
         Object[] previous = null;
         for (int d=size.length; --d >= 0;) {
+            final int p = empty[d];
             previous = (Object[]) walk;
-            walk = previous[empty[d]];
+            if (p >= previous.length) {
+                return numbers;
+            }
+            walk = previous[p];
             source[d] = size[d] / 2;
         }
+        assert walk == previous[empty[0]];
         if (walk == null) {
             previous[empty[0]] = tensor.apply(source);
         }
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Formatter.java 
b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Formatter.java
index 11a1d0c..ef162d1 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Formatter.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Formatter.java
@@ -525,7 +525,7 @@ public class Formatter implements Localized {
             if (colorApplied == 0) {
                 final String color = colors.getAnsiSequence(type);
                 if (color == null) {
-                    // Do not increment 'colorApplied' for giving a chance to 
children to apply their colors.
+                    // Do not increment `colorApplied` for giving a chance to 
children to apply their colors.
                     return;
                 }
                 final boolean isStart = (buffer.length() == elementStart);
@@ -1195,7 +1195,7 @@ public class Formatter implements Localized {
     public void append(final long number) {
         appendSeparator();
         /*
-         * The check for 'isComplement' is a hack for 
ImmutableIdentifier.formatTo(Formatter).
+         * The check for `isComplement` is a hack for 
ImmutableIdentifier.formatTo(Formatter).
          * We do not have a public API for controlling the integer colors (it 
may not be desirable).
          */
         setColor(isComplement ? ElementKind.IDENTIFIER : ElementKind.INTEGER);
@@ -1215,12 +1215,12 @@ public class Formatter implements Localized {
         setColor(ElementKind.NUMBER);
         /*
          * Use scientific notation if the number magnitude is too high or too 
low. The threshold values used here
-         * may be different than the threshold values used in the standard 
'StringBuilder.append(double)' method.
+         * may be different than the threshold values used in the standard 
`StringBuilder.append(double)` method.
          * In particular, we use a higher threshold for large numbers because 
ellipsoid axis lengths are above the
          * JDK threshold when the axis length is given in feet (about 2.1E+7) 
while we still want to format them
          * as usual numbers.
          *
-         * Note that we perform this special formatting only if the 
'NumberFormat' is not localized
+         * Note that we perform this special formatting only if the 
`NumberFormat` is not localized
          * (which is the usual case).
          */
         if (symbols.useScientificNotation(Math.abs(number))) {
@@ -1290,7 +1290,7 @@ public class Formatter implements Localized {
             marginBeforeRow = "";
         }
         /*
-         * 'formattedNumberMarks' contains, for each number in each row, 
positions in the 'buffer' where
+         * `formattedNumberMarks` contains, for each number in each row, 
positions in the `buffer` where
          * the number starts and position where it ends. Those positions are 
stored as (start,end) pairs.
          * We compute those marks unconditionally for simplicity, but will 
ignore them if formatting on
          * a single line.
@@ -1530,9 +1530,9 @@ public class Formatter implements Localized {
                     ((InternationalString) value).toString(locale) : 
value.toString(), null);
         } else if (value.getClass().isArray()) {
             /*
-             * All above cases delegated to another method which invoke 
'appendSeparator()'.
+             * All above cases delegated to another method which invoke 
`appendSeparator()`.
              * Since the following block is writing itself a new element, we 
need to invoke
-             * 'appendSeparator()' here. This block invokes (indirectly) this 
'appendValue'
+             * `appendSeparator()` here. This block invokes (indirectly) this 
`appendValue`
              * method recursively for some or all elements in the list.
              */
             appendSeparator();
@@ -1542,7 +1542,7 @@ public class Formatter implements Localized {
             for (int i=0; i<length; i++) {
                 if (i == cut) {
                     /*
-                     * Skip elements in the middle if the list is too long. 
The 'cut' index has been computed
+                     * Skip elements in the middle if the list is too long. 
The `cut` index has been computed
                      * in such a way that the number of elements to skip 
should be greater than 1, otherwise
                      * formatting the single missing element would often have 
been shorter.
                      */
@@ -1710,7 +1710,7 @@ public class Formatter implements Localized {
              * The unit that we replaced was not the expected one. Probably 
the user has invoked
              * addContextualUnit(…) again without a matching call to 
restoreContextualUnit(…).
              * Note that this case should never happen in 
Convention.WKT1_COMMON_UNITS mode,
-             * since 'previous' should never be non-null in that mode (if the 
user followed
+             * since `previous` should never be non-null in that mode (if the 
user followed
              * the documented pattern).
              */
             throw new IllegalStateException();
@@ -1752,7 +1752,7 @@ public class Formatter implements Localized {
         return (warnings != null) || (buffer != null && buffer.length() == 0);
         /*
          * Note: we really use a "and" condition (not an other "or") for the 
buffer test because
-         *       the buffer is reset to 'null' by WKTFormat after a 
successfull formatting.
+         *       the buffer is reset to `null` by WKTFormat after a 
successfull formatting.
          */
     }
 

Reply via email to