[gimp/gimp-2-10] plug-ins: fix #1146 DICOM with big endian transfer syntax fails to load.



commit e629e3e7d2dccd66853cc1b4b07eecd1ba5f47da
Author: Jacob Boerema <jgboerema gmail com>
Date:   Wed Jul 21 16:09:12 2021 -0400

    plug-ins: fix #1146 DICOM with big endian transfer syntax fails to load.
    
    Our plug-in was not correctly handling DICOM images that use big endian
    transfer syntax, which is deprecated.
    
    We add support for that here, add a few g_debug statements to make future
    debugging easier, and also return an error when we encounter a transfer
    syntax that we can't handle instead of blindly continuing.
    
    (cherry picked from commit e0707af073e52003928d375859b72d5e413d5770)
    
    # Conflicts:
    #       plug-ins/common/file-dicom.c

 plug-ins/common/file-dicom.c | 65 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 53 insertions(+), 12 deletions(-)
---
diff --git a/plug-ins/common/file-dicom.c b/plug-ins/common/file-dicom.c
index 3314add95b..b3e9ec6334 100644
--- a/plug-ins/common/file-dicom.c
+++ b/plug-ins/common/file-dicom.c
@@ -331,6 +331,8 @@ load_image (const gchar  *filename,
   guint8         *pix_buf           = NULL;
   gboolean        is_signed         = FALSE;
   guint8          in_sequence       = 0;
+  gboolean        implicit_encoding = FALSE;
+  gboolean        big_endian        = FALSE;
 
   gimp_progress_init_printf (_("Opening '%s'"),
                              gimp_filename_to_utf8 (filename));
@@ -382,8 +384,6 @@ load_image (const gchar  *filename,
       guint16  ctx_us;
       guint8  *value;
       guint32  tag;
-      gboolean __attribute__((unused))do_toggle_endian = FALSE;
-      gboolean implicit_encoding = FALSE;
 
       if (fread (&group_word, 1, 2, DICOM) == 0)
         break;
@@ -392,6 +392,12 @@ load_image (const gchar  *filename,
       fread (&element_word, 1, 2, DICOM);
       element_word = g_ntohs (GUINT16_SWAP_LE_BE (element_word));
 
+      if (group_word != 0x0002 && big_endian)
+        {
+          group_word   = GUINT16_SWAP_LE_BE (group_word);
+          element_word = GUINT16_SWAP_LE_BE (element_word);
+        }
+
       tag = (group_word << 16) | element_word;
       fread(value_rep, 2, 1, DICOM);
       value_rep[2] = 0;
@@ -428,8 +434,12 @@ load_image (const gchar  *filename,
           fread (&element_length_chars[2], 1, 2, DICOM);
 
           /* Now cast to integer and insert into element_length */
-          element_length =
-            g_ntohl (GUINT32_SWAP_LE_BE (*((gint *) element_length_chars)));
+          if (big_endian && group_word != 0x0002)
+            element_length =
+              g_ntohl (*((gint *) element_length_chars));
+          else
+            element_length =
+              g_ntohl (GUINT32_SWAP_LE_BE (*((gint *) element_length_chars)));
       }
       /* Binary value reps are OB, OW, SQ or UN */
       else if (strncmp (value_rep, "OB", 2) == 0
@@ -437,17 +447,23 @@ load_image (const gchar  *filename,
           || strncmp (value_rep, "SQ", 2) == 0
           || strncmp (value_rep, "UN", 2) == 0)
         {
-          fread (&element_length, 1, 2, DICOM); /* skip two bytes */
-          fread (&element_length, 1, 4, DICOM);
-          element_length = g_ntohl (GUINT32_SWAP_LE_BE (element_length));
+          fread (&element_length, 1, 2, dicom); /* skip two bytes */
+          fread (&element_length, 1, 4, dicom);
+          if (big_endian && group_word != 0x0002)
+            element_length = g_ntohl (element_length);
+          else
+            element_length = g_ntohl (GUINT32_SWAP_LE_BE (element_length));
         }
       /* Short length */
       else
         {
           guint16 el16;
 
-          fread (&el16, 1, 2, DICOM);
-          element_length = g_ntohs (GUINT16_SWAP_LE_BE (el16));
+          fread (&el16, 1, 2, dicom);
+          if (big_endian && group_word != 0x0002)
+            element_length = g_ntohs (el16);
+          else
+            element_length = g_ntohs (GUINT16_SWAP_LE_BE (el16));
         }
 
       /* Sequence of items - just ignore the delimiters... */
@@ -490,7 +506,12 @@ load_image (const gchar  *filename,
         }
       /* Some special casts that are used below */
       ctx_us = *(guint16 *) value;
+      if (big_endian && group_word != 0x0002)
+        ctx_us = GUINT16_SWAP_LE_BE (ctx_us);
 
+      g_debug ("group: %04x, element: %04x, length: %d",
+               group_word, element_word, element_length);
+      g_debug ("Value: %s", (char*)value);
       /* Recognize some critical tags */
       if (group_word == 0x0002)
         {
@@ -499,13 +520,33 @@ load_image (const gchar  *filename,
             case 0x0010:   /* transfer syntax id */
               if (strcmp("1.2.840.10008.1.2", (char*)value) == 0)
                 {
-                  do_toggle_endian = FALSE;
                   implicit_encoding = TRUE;
+                  g_debug ("Transfer syntax: Implicit VR Endian: Default Transfer Syntax for DICOM.");
                 }
               else if (strcmp("1.2.840.10008.1.2.1", (char*)value) == 0)
-                do_toggle_endian = FALSE;
+                {
+                  g_debug ("Transfer syntax: Explicit VR Little Endian.");
+                }
+              else if (strcmp("1.2.840.10008.1.2.1.99", (char*)value) == 0)
+                {
+                  g_debug ("Transfer syntax: Deflated Explicit VR Little Endian.");
+                }
               else if (strcmp("1.2.840.10008.1.2.2", (char*)value) == 0)
-                do_toggle_endian = TRUE;
+                {
+                  /* This Transfer Syntax was retired in 2006. For the most recent description of it, see 
PS3.5 2016b */
+                  big_endian = TRUE;
+                  g_debug ("Transfer syntax: Deprecated Explicit VR Big Endian.");
+                }
+              else
+                {
+                  g_debug ("Transfer syntax %s is not supported by GIMP.", (gchar *) value);
+                  g_set_error (error, GIMP_PLUG_IN_ERROR, 0,
+                              _("Transfer syntax %s is not supported by GIMP."),
+                              (gchar *) value);
+                  g_free (dicominfo);
+                  fclose (dicom);
+                  return NULL;
+                }
               break;
             }
         }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]