--- gimp-2.3.17/app/core/gimpbrush-load.c.orig	2007-06-02 15:01:24.000000000 +0200
+++ gimp-2.3.17/app/core/gimpbrush-load.c	2007-06-02 16:51:40.000000000 +0200
@@ -85,16 +85,36 @@
 
 
 /*  local function prototypes  */
-
-static GimpBrush * gimp_brush_load_abr_brush (FILE         *file,
-                                              AbrHeader    *abr_hdr,
-                                              gint          index,
-                                              const gchar  *filename,
-                                              GError      **error);
-static gchar       abr_read_char             (FILE         *file);
-static gint16      abr_read_short            (FILE         *file);
-static gint32      abr_read_long             (FILE         *file);
-static gchar     * abr_v2_read_brush_name    (FILE         *file);
+static GList     * gimp_brush_load_abr_v12      (FILE         *file,
+                                                 AbrHeader    *abr_hdr,
+                                                 const gchar  *filename,
+                                                 GError      **error);
+static GList     * gimp_brush_load_abr_v6       (FILE         *file,
+                                                 AbrHeader    *abr_hdr,
+                                                 const gchar  *filename,
+                                                 GError      **error);
+static GimpBrush * gimp_brush_load_abr_brush    (FILE         *file,
+                                                 AbrHeader    *abr_hdr,
+                                                 gint          index,
+                                                 const gchar  *filename,
+                                                 GError      **error);
+static GimpBrush * gimp_brush_load_abr_brush_v6 (FILE         *file,
+                                                 AbrHeader    *abr_hdr,
+                                                 gint32        max_offset,
+                                                 gint          index,
+                                                 const gchar  *filename,
+                                                 GError      **error);
+
+static gchar       abr_read_char                (FILE         *file);
+static gint16      abr_read_short               (FILE         *file);
+static gint32      abr_read_long                (FILE         *file);
+static gchar     * abr_read_ucs2_text           (FILE         *file);
+static gboolean    abr_supported                (AbrHeader    *abr_hdr);
+static gboolean    abr_reach_8bim_section       (FILE         *abr,
+                                                 const gchar  *name);
+static gint32      rle_decode                   (FILE         *abr,
+                                                 gchar        *buffer,
+                                                 gint32        height);
 
 
 /*  public functions  */
@@ -400,47 +420,192 @@
     }
 
   abr_hdr.version = abr_read_short (file);
-  abr_hdr.count   = abr_read_short (file);
-
-  /* g_print("version: %d  count: %d\n", abr_hdr.version, abr_hdr.count); */
+  abr_hdr.count   = abr_read_short (file); /* sub-version for ABR v6 */
 
-  if (abr_hdr.version > 2)
+  if (abr_supported (&abr_hdr))
     {
+      switch (abr_hdr.version)
+        {
+        case 1:
+        case 2:
+          brush_list = gimp_brush_load_abr_v12 (file, &abr_hdr,
+                                                filename, error);
+          break;
+        case 6:
+          brush_list = gimp_brush_load_abr_v6 (file, &abr_hdr,
+                                               filename, error);
+        }
+    }
+
+  fclose (file);
+
+  if (!brush_list)
       g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
                    _("Fatal parse error in brush file '%s': "
                      "unable to decode abr format version %d."),
                    gimp_filename_to_utf8 (filename), abr_hdr.version);
-    }
-  else
+
+  return g_list_reverse (brush_list);
+}
+
+
+/*  private functions  */
+static GList *
+gimp_brush_load_abr_v12 (FILE         *file,
+                         AbrHeader    *abr_hdr,
+                         const gchar  *filename,
+                         GError      **error)
+{
+  gint       i;
+  GList     *brush_list = NULL;
+  
+  for (i = 0; i < abr_hdr->count; i++)
     {
-      gint i;
+      GimpBrush *brush;
+
+      brush = gimp_brush_load_abr_brush (file, abr_hdr, i,
+                                         filename, error);
 
-      for (i = 0; i < abr_hdr.count; i++)
+      if (! brush)
         {
-          GimpBrush *brush;
+          g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
+                       _("Fatal parse error in brush file '%s'"),
+                       gimp_filename_to_utf8 (filename));
+          break;
+        }
 
-          brush = gimp_brush_load_abr_brush (file, &abr_hdr, i,
-                                             filename, error);
+      brush_list = g_list_prepend (brush_list, brush);
+    }
 
-          if (! brush)
-            {
-              g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
-                           _("Fatal parse error in brush file '%s'"),
-                           gimp_filename_to_utf8 (filename));
-              break;
-            }
+  return brush_list;
+}
 
-          brush_list = g_list_prepend (brush_list, brush);
+static GList *
+gimp_brush_load_abr_v6 (FILE         *file,
+                        AbrHeader    *abr_hdr,
+                        const gchar  *filename,
+                        GError      **error)
+{
+  GList     *brush_list = NULL;
+  gint32     sample_section_size;
+  gint32     sample_section_end;
+  gint       index = 1;
+
+  if (! abr_reach_8bim_section (file, "samp"))
+    return brush_list;
+
+  sample_section_size = abr_read_long (file);
+  sample_section_end = sample_section_size + ftell (file);
+  
+  while (ftell (file) < sample_section_end)
+    {
+      GimpBrush *brush;
+
+      brush = gimp_brush_load_abr_brush_v6 (file, abr_hdr, sample_section_end,
+                                            index, filename, error);
+
+      if (! brush)
+        {
+          g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
+                       _("Fatal parse error in brush file '%s'"),
+                       gimp_filename_to_utf8 (filename));
+          break;
         }
-    }
 
-  fclose (file);
+      index ++;
+      brush_list = g_list_prepend (brush_list, brush);
+    }
 
-  return g_list_reverse (brush_list);
+  return brush_list;
 }
 
+static GimpBrush *
+gimp_brush_load_abr_brush_v6 (FILE         *file,
+                              AbrHeader    *abr_hdr,
+                              gint32        max_offset,
+                              gint          index,
+                              const gchar  *filename,
+                              GError      **error)
+{
+  GimpBrush      *brush = NULL;
+  guchar         *mask;
 
-/*  private functions  */
+  gint32          brush_size;
+  gint32          brush_end;
+  gint32          complement_to_4;
+  gint32          next_brush;
+
+  gint32          top, left, bottom, right;
+  gint16          depth;
+  gchar           compress;
+
+  gint32          width, height;
+  gint32          size;
+
+  gchar          *tmp;
+  gchar          *name;
+  gint r;
+
+  brush_size = abr_read_long (file);
+  brush_end = brush_size;
+  /* complement to 4 */
+  while (brush_end % 4 != 0) brush_end++;
+  complement_to_4 = brush_end - brush_size;
+  next_brush = ftell (file) + brush_end;
+
+  if (abr_hdr->count == 1)
+    /* discard key and short coordinates and unknown short */
+    r = fseek (file, 47, SEEK_CUR);
+  else
+    /* discard key and unknown bytes */
+    r = fseek (file, 301, SEEK_CUR);
+
+  if (r == -1)
+    return brush;
+
+  top = abr_read_long (file);
+  left = abr_read_long (file);
+  bottom = abr_read_long (file);
+  right = abr_read_long (file);
+  depth = abr_read_short (file);
+  compress = abr_read_char (file);
+
+  width = right - left;
+  height = bottom - top;
+  size = width * (depth >> 3) * height;
+
+  tmp = g_filename_display_basename (filename);
+  name = g_strdup_printf ("%s-%03d", tmp, index);
+  g_free (tmp);
+
+  brush = g_object_new (GIMP_TYPE_BRUSH,
+                        "name",      name,
+                        /*  FIXME: MIME type!!  */
+                        "mime-type", "application/x-photoshop-abr",
+                        NULL);
+
+  g_free (name);
+
+  brush->spacing  = 25; /* real value needs 8BIMdesc section parser */
+  brush->x_axis.x = width / 2.0;
+  brush->x_axis.y = 0.0;
+  brush->y_axis.x = 0.0;
+  brush->y_axis.y = height / 2.0;
+  brush->mask     = temp_buf_new (width, height, 1, 0, 0, NULL);
+
+  mask = temp_buf_data (brush->mask);
+
+  /* data decoding */
+  if (!compress)
+    /* not compressed - read raw bytes as brush data */
+    fread (mask, size, 1, file);
+  else
+    rle_decode (file, (gchar*) mask, height);
+
+  fseek (file, next_brush, SEEK_SET);
+
+  return brush;
+}
 
 static GimpBrush *
 gimp_brush_load_abr_brush (FILE         *file,
@@ -483,7 +648,8 @@
         gint                   size;
         guchar                *mask;
         gint                   i;
-        gchar                 *name = NULL;
+        gchar                 *name;
+        gchar                 *sample_name = NULL;
         gchar                 *tmp;
         gshort                 compress;
 
@@ -491,7 +657,7 @@
         abr_sampled_brush_hdr.spacing = abr_read_short (file);
 
         if (abr_hdr->version == 2)
-          name = abr_v2_read_brush_name (file);
+          sample_name = abr_read_ucs2_text (file);
 
         abr_sampled_brush_hdr.antialiasing = abr_read_char (file);
 
@@ -521,12 +687,17 @@
             return NULL;
           }
 
-        if (! name)
+        tmp = g_filename_display_basename (filename);
+        if (! sample_name)
+          /* build name from filename and index */
+          name = g_strdup_printf ("%s-%03d", tmp, index);
+        else
           {
-            tmp = g_filename_display_basename (filename);
-            name = g_strdup_printf ("%s-%03d", tmp, index);
-            g_free (tmp);
+            /* build name from filename and sample name */
+            name = g_strdup_printf ("%s-%s", tmp, sample_name);
+            g_free(sample_name);
           }
+        g_free (tmp);
 
         brush = g_object_new (GIMP_TYPE_BRUSH,
                               "name",      name,
@@ -554,59 +725,9 @@
          */
 
         if (! compress)
-          {
-            fread (mask, size, 1, file);
-          }
+          fread (mask, size, 1, file);
         else
-          {
-            gint16 *cscanline_len;
-            gint32  n;
-            gchar   ch;
-            gint    i, j, c;
-
-            /* read compressed size foreach scanline */
-            cscanline_len = g_new0 (gshort, height);
-
-            for (i = 0; i < height; i++)
-              cscanline_len[i] = abr_read_short (file);
-
-            /* unpack each scanline data */
-            for (i = 0; i < height; i++)
-              {
-                for (j = 0; j < cscanline_len[i];)
-                  {
-                    n = abr_read_char (file);
-                    j++;
-
-                    if (n >= 128)       /* force sign */
-                      n -= 256;
-
-                    if (n < 0)
-                      {
-                        /* copy the following char -n + 1 times */
-
-                        if (n == -128)    /* it's a nop */
-                          continue;
-
-                        n = -n + 1;
-                        ch = abr_read_char (file);
-                        j++;
-
-                        for (c = 0; c < n; c++, mask++)
-                          *mask = ch;
-                      }
-                    else
-                      {
-                        /* read the following n + 1 chars (no compr) */
-
-                        for (c = 0; c < n + 1; c++, j++, mask++)
-                          *mask = (guchar) abr_read_char (file);
-                      }
-                  }
-              }
-
-            g_free (cscanline_len);
-          }
+          rle_decode (file, (gchar*) mask, height);
       }
       break;
 
@@ -646,7 +767,7 @@
 }
 
 static gchar *
-abr_v2_read_brush_name (FILE *file)
+abr_read_ucs2_text (FILE *file)
 {
   gchar *name_ucs2;
   gchar *name_utf8;
@@ -676,3 +797,102 @@
 
   return name_utf8;
 }
+
+static gboolean
+abr_supported (AbrHeader *abr_hdr)
+{
+  switch (abr_hdr->version)
+    {
+    case 1:
+    case 2:
+      return TRUE;
+      break;
+    case 6:
+      /* in this case, count contains format sub-version */
+      if (abr_hdr->count == 1 || abr_hdr->count == 2)
+        return TRUE;
+      break;
+    }
+  return FALSE;
+}
+
+static gboolean
+abr_reach_8bim_section (FILE* abr, const gchar *name)
+{
+  gchar  tag[4];
+  gchar  tagname[5];
+  gint32 section_size;
+  gint   r;
+
+  while (! feof (abr))
+    {
+      r = fread (&tag, 1, 4, abr);
+      if (r != 4)
+        return FALSE;
+      
+      if (strncmp (tag, "8BIM", 4))
+        return FALSE;
+
+      r = fread (&tagname, 1, 4, abr);
+      if (r != 4)
+        return FALSE;
+
+      tagname[4] = '\0';
+
+      if (!strncmp (tagname, name, 4))
+        return TRUE;
+    
+      section_size = abr_read_long (abr);
+      r = fseek (abr, section_size, SEEK_CUR);
+      if (r == -1)
+        return FALSE;
+    }
+  return FALSE;
+}
+
+static gint32
+rle_decode (FILE  *abr,
+            gchar *buffer,
+            gint32 height)
+{
+  gint32   n;
+  gchar    ch;
+  gint     i, j, c;
+  gshort  *cscanline_len;
+  gchar   *data = buffer;
+
+  /* read compressed size foreach scanline */
+  cscanline_len = g_new0 (gshort, height);
+  for (i = 0; i < height; i++)
+    cscanline_len[i] = abr_read_short (abr);
+  
+  /* unpack each scanline data */
+  for (i = 0; i < height; i++)
+    {
+      for (j = 0; j < cscanline_len[i];)
+        {
+          n = abr_read_char (abr);
+          j++;
+          if (n >= 128)     /* force sign */
+            n -= 256;
+          if (n < 0)
+            {      /* copy the following char -n + 1 times */
+              if (n == -128)  /* it's a nop */
+                continue;
+              n = -n + 1;
+              ch = abr_read_char (abr);
+              j++;
+              for (c = 0; c < n; c++, data++)
+                *data = ch;
+            }
+          else
+            {          /* read the following n + 1 chars (no compr) */
+              for (c = 0; c < n + 1; c++, j++, data++)
+                *data = abr_read_char (abr);
+            }
+        }
+    }
+  g_free (cscanline_len);
+
+  return 0;
+}
