JAL-4366 avoid corrupting map when no complete mapping available for chain to sequence
[jalview.git] / src / jalview / io / gff / GffHelperBase.java
index ee93c55..0097343 100644 (file)
@@ -43,6 +43,8 @@ import java.util.Map.Entry;
  */
 public abstract class GffHelperBase implements GffHelperI
 {
+  private static final String INVALID_GFF_ATTRIBUTE_FORMAT = "Invalid GFF attribute format: ";
+
   protected static final String COMMA = ",";
 
   protected static final String EQUALS = "=";
@@ -112,8 +114,9 @@ public abstract class GffHelperBase implements GffHelperI
      */
     if (!trimMapping(from, to, fromRatio, toRatio))
     {
-      System.err.println("Ignoring mapping from " + Arrays.toString(from)
-              + " to " + Arrays.toString(to) + " as counts don't match!");
+      jalview.bin.Console.errPrintln(
+              "Ignoring mapping from " + Arrays.toString(from) + " to "
+                      + Arrays.toString(to) + " as counts don't match!");
       return null;
     }
 
@@ -164,7 +167,7 @@ public abstract class GffHelperBase implements GffHelperI
       {
         from[1] += fromOverlap / toRatio;
       }
-      System.err.println(Arrays.toString(from));
+      jalview.bin.Console.errPrintln(Arrays.toString(from));
       return true;
     }
     else if (fromOverlap < 0 && fromOverlap % fromRatio == 0)
@@ -183,7 +186,7 @@ public abstract class GffHelperBase implements GffHelperI
       {
         to[1] += fromOverlap / fromRatio;
       }
-      System.err.println(Arrays.toString(to));
+      jalview.bin.Console.errPrintln(Arrays.toString(to));
       return true;
     }
 
@@ -379,7 +382,8 @@ public abstract class GffHelperBase implements GffHelperI
    * @return
    */
   protected SequenceFeature buildSequenceFeature(String[] gff,
-          int typeColumn, String group, Map<String, List<String>> attributes)
+          int typeColumn, String group,
+          Map<String, List<String>> attributes)
   {
     try
     {
@@ -441,7 +445,8 @@ public abstract class GffHelperBase implements GffHelperI
       return sf;
     } catch (NumberFormatException nfe)
     {
-      System.err.println("Invalid number in gff: " + nfe.getMessage());
+      jalview.bin.Console
+              .errPrintln("Invalid number in gff: " + nfe.getMessage());
       return null;
     }
   }
@@ -466,6 +471,45 @@ public abstract class GffHelperBase implements GffHelperI
   {
     Map<String, String> map = new HashMap<>();
     String[] fields = s.split(EQUALS);
+
+    /*
+     * format validation
+     */
+    boolean valid = true;
+    if (fields.length < 2)
+    {
+      /*
+       * need at least A=B here
+       */
+      valid = false;
+    }
+    else if (fields[0].isEmpty() || fields[0].contains(COMMA))
+    {
+      /*
+       * A,B=C is not a valid start, nor is =C
+       */
+      valid = false;
+    }
+    else
+    {
+      for (int i = 1; i < fields.length - 1; i++)
+      {
+        if (fields[i].isEmpty() || !fields[i].contains(COMMA))
+        {
+          /*
+           * intermediate tokens must include value,name
+           */
+          valid = false;
+        }
+      }
+    }
+
+    if (!valid)
+    {
+      jalview.bin.Console.errPrintln(INVALID_GFF_ATTRIBUTE_FORMAT + s);
+      return map;
+    }
+
     int i = 0;
     while (i < fields.length - 1)
     {
@@ -481,6 +525,14 @@ public abstract class GffHelperBase implements GffHelperI
               ? before.substring(before.lastIndexOf(COMMA) + 1)
               : before;
 
+      theKey = theKey.trim();
+      if (theKey.isEmpty())
+      {
+        jalview.bin.Console.errPrintln(INVALID_GFF_ATTRIBUTE_FORMAT + s);
+        map.clear();
+        return map;
+      }
+
       /*
        * if 'value' looks like a,b,c then all but the last token is the value,
        * unless this is the last field (no more = to follow), in which case