[easytag] Use GBytes for image data inside Picture



commit 2f38620fdfce98ed381ac9b72a6f8d82ca4d0c63
Author: David King <amigadave amigadave com>
Date:   Wed Dec 17 17:10:39 2014 +0000

    Use GBytes for image data inside Picture
    
    Avoid many superfluous memory allocations when copying Picture instances
    by using GBytes instead of a bare pointer, and incrementing the
    reference count when copying. Use the slice allocator to allocate
    Picture instances. Avoid Picture->bytes from ever being NULL. Update the
    Picture tests.
    
    Inspired by a report of excessive memory usage on the mailing list:
    
    https://mail.gnome.org/archives/easytag-list/2014-December/msg00000.html

 src/et_core.c         |   11 +--
 src/et_core.h         |    9 +-
 src/picture.c         |  118 +++++++++++++-----------
 src/picture.h         |    3 +-
 src/tag_area.c        |   16 ++--
 src/tags/flac_tag.c   |   12 ++-
 src/tags/id3_tag.c    |    8 ++-
 src/tags/id3v24_tag.c |   29 ++++--
 src/tags/mp4_tag.cc   |   13 ++-
 src/tags/ogg_tag.c    |  240 +++++++++++++++++++++++++------------------------
 tests/test-picture.c  |   14 ++--
 11 files changed, 253 insertions(+), 220 deletions(-)
---
diff --git a/src/et_core.c b/src/et_core.c
index 9143924..e7c1044 100644
--- a/src/et_core.c
+++ b/src/et_core.c
@@ -3913,15 +3913,10 @@ ET_Detect_Changes_Of_File_Tag (const File_Tag *FileTag1,
         //if (!pic1->data || !pic2->data)
         //    break; // => no changes
 
-        if (!pic1->data && !pic2->data)
-            return FALSE;
-        if (pic1->data && !pic2->data)
-            return TRUE;
-        if (!pic1->data && pic2->data)
-            return TRUE;
-        if (pic1->size != pic2->size
-        ||  memcmp(pic1->data, pic2->data, pic1->size))
+        if (!g_bytes_equal (pic1->bytes, pic2->bytes))
+        {
             return TRUE;
+        }
         if (pic1->type != pic2->type)
             return TRUE;
         if (pic1->description && !pic2->description
diff --git a/src/et_core.h b/src/et_core.h
index af52c39..1c520df 100644
--- a/src/et_core.h
+++ b/src/et_core.h
@@ -22,11 +22,11 @@
 
 #include "setting.h"
 
+G_BEGIN_DECLS
+
 #include <glib.h>
 #include <gdk/gdk.h>
 
-G_BEGIN_DECLS
-
 /*
  * Colors Used (see declaration into et_core.c)
  */
@@ -88,12 +88,11 @@ struct _File_Name
 typedef struct _Picture Picture;
 struct _Picture
 {
-    gint     type;
+    gint type;
     gchar   *description;
     gint     width;         /* Original width of the picture */
     gint     height;        /* Original height of the picture */
-    gsize size; /* Picture size in bytes (like stat) */
-    guchar  *data;
+    GBytes *bytes;
     Picture *next;
 };
 
diff --git a/src/picture.c b/src/picture.c
index 6a64d6f..c2f4d0c 100644
--- a/src/picture.c
+++ b/src/picture.c
@@ -111,42 +111,33 @@ et_picture_type_from_filename (const gchar *filename_utf8)
 Picture_Format
 Picture_Format_From_Data (const Picture *pic)
 {
-    // JPEG : "\xff\xd8"
-    if (pic->data && pic->size > 2
-    &&  pic->data[0] == 0xff
-    &&  pic->data[1] == 0xd8)
+    gsize size;
+    gconstpointer data;
+
+    g_return_val_if_fail (pic != NULL, PICTURE_FORMAT_UNKNOWN);
+
+    data = g_bytes_get_data (pic->bytes, &size);
+
+    /* JPEG : "\xff\xd8". */
+    if (size > 2 && memcmp (data, "\xff\xd8", 2))
+    {
         return PICTURE_FORMAT_JPEG;
+    }
 
-    // PNG : "\x89PNG\x0d\x0a\x1a\x0a"
-    if (pic->data && pic->size > 8
-    &&  pic->data[0] == 0x89
-    &&  pic->data[1] == 0x50
-    &&  pic->data[2] == 0x4e
-    &&  pic->data[3] == 0x47
-    &&  pic->data[4] == 0x0d
-    &&  pic->data[5] == 0x0a
-    &&  pic->data[6] == 0x1a
-    &&  pic->data[7] == 0x0a)
+    /* PNG : "\x89PNG\x0d\x0a\x1a\x0a". */
+    if (size > 8 && memcmp (data, "\x89PNG\x0d\x0a\x1a\x0a", 8))
+    {
         return PICTURE_FORMAT_PNG;
+    }
     
     /* GIF: "GIF87a" */
-    if (pic->data && pic->size > 6
-    &&  pic->data[0] == 0x47
-    &&  pic->data[1] == 0x49
-    &&  pic->data[2] == 0x46
-    &&  pic->data[3] == 0x38
-    &&  pic->data[4] == 0x37
-    &&  pic->data[5] == 0x61)
+    if (size > 6 && memcmp (data, "GIF87a", 6))
+    {
         return PICTURE_FORMAT_GIF;
+    }
 
     /* GIF: "GIF89a" */
-    if (pic->data && pic->size > 6
-        &&  pic->data[0] == 0x47
-        &&  pic->data[1] == 0x49
-        &&  pic->data[2] == 0x46
-        &&  pic->data[3] == 0x38
-        &&  pic->data[4] == 0x39
-        &&  pic->data[5] == 0x61)
+    if (size > 6 && memcmp (data, "GIF89a", 6))
     {
         return PICTURE_FORMAT_GIF;
     }
@@ -154,7 +145,8 @@ Picture_Format_From_Data (const Picture *pic)
     return PICTURE_FORMAT_UNKNOWN;
 }
 
-const gchar *Picture_Mime_Type_String (Picture_Format format)
+const gchar *
+Picture_Mime_Type_String (Picture_Format format)
 {
     switch (format)
     {
@@ -255,8 +247,8 @@ Picture_Info (const Picture *pic,
     else
         desc = "";
 
-    type = Picture_Type_String(pic->type);
-    size_str = g_format_size (pic->size);
+    type = Picture_Type_String (pic->type);
+    size_str = g_format_size (g_bytes_get_size (pic->bytes));
 
     // Behaviour following the tag type...
     switch (tag_type)
@@ -285,34 +277,37 @@ Picture_Info (const Picture *pic,
     return r;
 }
 
-Picture *Picture_Allocate (void)
+Picture *
+Picture_Allocate (void)
 {
-    Picture *pic = g_malloc0(sizeof(Picture));
+    Picture *pic = g_slice_new0 (Picture);
     return pic;
 }
 
-Picture *Picture_Copy_One (const Picture *pic)
+Picture *
+Picture_Copy_One (const Picture *pic)
 {
     Picture *pic2;
 
     g_return_val_if_fail (pic != NULL, NULL);
 
-    pic2 = Picture_Allocate();
+    pic2 = Picture_Allocate ();
     pic2->type = pic->type;
     pic2->width  = pic->width;
     pic2->height = pic->height;
+
     if (pic->description)
-        pic2->description = g_strdup(pic->description);
-    if (pic->data)
     {
-        pic2->size = pic->size;
-        pic2->data = g_malloc(pic2->size);
-        memcpy(pic2->data, pic->data, pic->size);
+        pic2->description = g_strdup (pic->description);
     }
+
+    pic2->bytes = g_bytes_ref (pic->bytes);
+
     return pic2;
 }
 
-Picture *Picture_Copy (const Picture *pic)
+Picture *
+Picture_Copy (const Picture *pic)
 {
     Picture *pic2 = Picture_Copy_One(pic);
     if (pic->next)
@@ -320,17 +315,24 @@ Picture *Picture_Copy (const Picture *pic)
     return pic2;
 }
 
-void Picture_Free (Picture *pic)
+void
+Picture_Free (Picture *pic)
 {
-    if (!pic)
+    if (pic == NULL)
+    {
         return;
+    }
+
     if (pic->next)
-        Picture_Free(pic->next);
-    if (pic->description)
-        g_free(pic->description);
-    if (pic->data)
-        g_free(pic->data);
-    g_free(pic);
+    {
+        Picture_Free (pic->next);
+    }
+
+    g_free (pic->description);
+    g_bytes_unref (pic->bytes);
+    pic->bytes = NULL;
+
+    g_slice_free (Picture, pic);
 }
 
 
@@ -397,6 +399,8 @@ et_picture_load_file_data (GFile *file, GError **error)
     {
         /* Image loaded. */
         Picture *pic;
+        gpointer data;
+        gsize data_size;
 
         g_object_unref (file_istream);
 
@@ -410,8 +414,10 @@ et_picture_load_file_data (GFile *file, GError **error)
         g_assert (error == NULL || *error == NULL);
 
         pic = Picture_Allocate ();
-        pic->data = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (ostream));
-        pic->size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (ostream));
+        data = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (ostream));
+        data_size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (ostream));
+        pic->bytes = g_bytes_new_take (data, data_size);
+        /* TODO: Use g_memory_output_stream_steal_as_bytes(). */
 
         g_object_unref (ostream);
         g_assert (error == NULL || *error == NULL);
@@ -433,6 +439,8 @@ gboolean
 et_picture_save_file_data (const Picture *pic, GFile *file, GError **error)
 {
     GFileOutputStream *file_ostream;
+    gconstpointer data;
+    gsize data_size;
     gsize bytes_written;
 
     g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -446,12 +454,14 @@ et_picture_save_file_data (const Picture *pic, GFile *file, GError **error)
         return FALSE;
     }
 
-    if (!g_output_stream_write_all (G_OUTPUT_STREAM (file_ostream), pic->data,
-                                    pic->size, &bytes_written, NULL, error))
+    data = g_bytes_get_data (pic->bytes, &data_size);
+
+    if (!g_output_stream_write_all (G_OUTPUT_STREAM (file_ostream), data,
+                                    data_size, &bytes_written, NULL, error))
     {
         g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %" G_GSIZE_FORMAT
                  " bytes of picture data were written", bytes_written,
-                 pic->size);
+                 g_bytes_get_size (pic->bytes));
         g_object_unref (file_ostream);
         g_assert (error == NULL || *error != NULL);
         return FALSE;
diff --git a/src/picture.h b/src/picture.h
index 2363dfc..bb8f2d1 100644
--- a/src/picture.h
+++ b/src/picture.h
@@ -32,8 +32,7 @@ struct _Picture
     gchar   *description;
     gint     width;         // Original width of the picture
     gint     height;        // Original height of the picture
-    gulong   size;          // Picture size in bits
-    guchar  *data;
+    GBytes *bytes;
     Picture *next;
 };*/
 
diff --git a/src/tag_area.c b/src/tag_area.c
index 30c2dfb..c6968c3 100644
--- a/src/tag_area.c
+++ b/src/tag_area.c
@@ -1223,6 +1223,8 @@ PictureEntry_Clear (EtTagArea *self)
 
     model = GTK_TREE_MODEL (priv->images_model);
 
+    /* FIXME: Make Picture a boxed type, so that it can be freed
+     * automatically. */
     if (gtk_tree_model_get_iter_first (model, &iter))
     {
         do
@@ -1248,17 +1250,17 @@ PictureEntry_Update (EtTagArea *self,
 
     priv = et_tag_area_get_instance_private (self);
 
-    if (!pic->data)
-    {
-        PictureEntry_Clear (self);
-        return;
-    }
-
     loader = gdk_pixbuf_loader_new ();
 
     if (loader)
     {
-        if (gdk_pixbuf_loader_write(loader, pic->data, pic->size, &error))
+        gconstpointer data;
+        gsize data_size;
+
+        data = g_bytes_get_data (pic->bytes, &data_size);
+
+        /* TODO: Use gdk_pixbuf_loader_write_bytes(). */
+        if (gdk_pixbuf_loader_write (loader, data, data_size, &error))
         {
             GtkTreeSelection *selection;
             GdkPixbuf *pixbuf;
diff --git a/src/tags/flac_tag.c b/src/tags/flac_tag.c
index e659210..7156fcb 100644
--- a/src/tags/flac_tag.c
+++ b/src/tags/flac_tag.c
@@ -678,8 +678,7 @@ flac_tag_read_file_tag (GFile *file,
                     prev_pic->next = pic;
                 prev_pic = pic;
 
-                pic->size = p->data_length;
-                pic->data = g_memdup(p->data,pic->size);
+                pic->bytes = g_bytes_new (p->data, p->data_length);
                 pic->type = p->type;
                 pic->description = g_strdup((gchar *)p->description);
                 // Not necessary: will be calculated later
@@ -1077,11 +1076,14 @@ flac_tag_write_file_tag (const ET_File *ETFile,
         Picture *pic = FileTag->picture;
         while (pic)
         {
-            if (pic->data)
+            /* TODO: Can this ever be NULL? */
+            if (pic->bytes)
             {
                 const gchar *violation;
                 FLAC__StreamMetadata *picture_block; // For picture data
                 Picture_Format format;
+                gconstpointer data;
+                gsize data_size;
                 
                 // Allocate block for picture data
                 picture_block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE);
@@ -1107,8 +1109,10 @@ flac_tag_write_file_tag (const ET_File *ETFile,
                 picture_block->data.picture.depth  = 0;
 
                 /* Picture data. */
+                data = g_bytes_get_data (pic->bytes, &data_size);
                 FLAC__metadata_object_picture_set_data (picture_block,
-                                                        (FLAC__byte *)pic->data, (FLAC__uint32) pic->size,
+                                                        (FLAC__byte *)data,
+                                                        (FLAC__uint32)data_size,
                                                         TRUE);
                 
                 if (!FLAC__metadata_object_picture_is_legal (picture_block,
diff --git a/src/tags/id3_tag.c b/src/tags/id3_tag.c
index 7300600..e755c7a 100644
--- a/src/tags/id3_tag.c
+++ b/src/tags/id3_tag.c
@@ -520,7 +520,13 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
             Id3tag_Set_Field(id3_frame, ID3FN_DESCRIPTION, pic->description);
 
         if ((id3_field = ID3Frame_GetField(id3_frame,ID3FN_DATA)))
-            ID3Field_SetBINARY(id3_field, pic->data, pic->size);
+        {
+            gconstpointer data;
+            gsize data_size;
+
+            data = g_bytes_get_data (pic->bytes, &data_size);
+            ID3Field_SetBINARY (id3_field, data, data_size);
+        }
 
         has_picture = TRUE;
     }
diff --git a/src/tags/id3v24_tag.c b/src/tags/id3v24_tag.c
index a6b4dca..8c5159a 100644
--- a/src/tags/id3v24_tag.c
+++ b/src/tags/id3v24_tag.c
@@ -456,9 +456,7 @@ id3tag_read_file_tag (GFile *gfile,
             prev_pic->next = pic;
         prev_pic = pic;
 
-        pic->data = NULL;
-
-        // Picture file data
+        /* Picture file data. */
         for (j = 0; (field = id3_frame_field(frame, j)); j++)
         {
             switch (id3_field_type(field))
@@ -468,14 +466,21 @@ id3tag_read_file_tag (GFile *gfile,
                         id3_length_t size;
                         id3_byte_t const *data;
                         
-                        data = id3_field_getbinarydata(field, &size);
-                        if (pic->data)
-                            g_free(pic->data);
-                        if ( data && (pic->data = g_memdup(data, size)) )
-                            pic->size = size;
+                        data = id3_field_getbinarydata (field, &size);
+
+                        if (data)
+                        {
+                            if (pic->bytes)
+                            {
+                                g_bytes_unref (pic->bytes);
+                            }
+
+                            pic->bytes = g_bytes_new (data, size);
+                        }
                     }
                     break;
                 case ID3_FIELD_TYPE_INT8:
+                    /* TODO: Verify that the type matches with EtPictureType. */
                     pic->type = id3_field_getint(field);
                     break;
                 default:
@@ -1157,7 +1162,13 @@ id3tag_write_file_v24tag (const ET_File *ETFile,
                         id3_field_setint(field, pic->type);
                         break;
                     case ID3_FIELD_TYPE_BINARYDATA:
-                        id3_field_setbinarydata(field, pic->data, pic->size);
+                        {
+                            gconstpointer data;
+                            gsize data_size;
+
+                            data = g_bytes_get_data (pic->bytes, &data_size);
+                            id3_field_setbinarydata (field, data, data_size);
+                        }
                         break;
                     default:
                         break;
diff --git a/src/tags/mp4_tag.cc b/src/tags/mp4_tag.cc
index f03a2d2..7be5b9e 100644
--- a/src/tags/mp4_tag.cc
+++ b/src/tags/mp4_tag.cc
@@ -211,9 +211,9 @@ mp4tag_read_file_tag (GFile *file,
 
         FileTag->picture = Picture_Allocate ();
 
-        FileTag->picture->size = art.data ().size ();
-        FileTag->picture->data = (guchar *)g_memdup (art.data ().data (),
-                                                     art.data ().size ());
+        /* TODO: Use g_bytes_new_with_free_func()? */
+        FileTag->picture->bytes = g_bytes_new (art.data ().data (),
+                                               art.data ().size ());
     }
     else
     {
@@ -438,6 +438,8 @@ mp4tag_write_file_tag (const ET_File *ETFile,
     {
         Picture_Format pf;
         TagLib::MP4::CoverArt::Format f;
+        gconstpointer data;
+        gsize data_size;
 
         pf = Picture_Format_From_Data (FileTag->picture);
 
@@ -458,8 +460,9 @@ mp4tag_write_file_tag (const ET_File *ETFile,
                 break;
         }
 
-        TagLib::MP4::CoverArt art (f, TagLib::ByteVector((char *)FileTag->picture->data,
-                                                         FileTag->picture->size));
+        data = g_bytes_get_data (FileTag->picture->bytes, &data_size);
+        TagLib::MP4::CoverArt art (f, TagLib::ByteVector((char *)data,
+                                                         data_size));
 
         extra_items.insert ("covr",
                             TagLib::MP4::Item (TagLib::MP4::CoverArtList ().append (art)));
diff --git a/src/tags/ogg_tag.c b/src/tags/ogg_tag.c
index 2bdcbce..fe2aba2 100644
--- a/src/tags/ogg_tag.c
+++ b/src/tags/ogg_tag.c
@@ -120,13 +120,16 @@ convert_to_byte_array (guint32 n, guchar *array)
  */
 
 static void
-add_to_guchar_str (guchar *ustr, gsize *ustr_len, guchar *str, gsize str_len)
+add_to_guchar_str (guchar *ustr,
+                   gsize *ustr_len,
+                   const guchar *str,
+                   gsize str_len)
 {
     gsize i;
 
     for (i = *ustr_len; i < *ustr_len + str_len; i++)
     {
-        ustr [i] = str [i - *ustr_len];
+        ustr[i] = str[i - *ustr_len];
     }
 
     *ustr_len += str_len;
@@ -479,6 +482,8 @@ et_add_file_tags_from_vorbis_comments (vorbis_comment *vc,
     while ( (string = vorbis_comment_query(vc,"COVERART",field_num++)) != NULL )
     {
         Picture *pic;
+        guchar *data;
+        gsize data_size;
             
         /* Force marking the file as modified, so that the deprecated cover art
          * field in converted in a METADATA_PICTURE_BLOCK field. */
@@ -491,10 +496,9 @@ et_add_file_tags_from_vorbis_comments (vorbis_comment *vc,
             prev_pic->next = pic;
         prev_pic = pic;
 
-        pic->data = NULL;
-        
-        // Decode picture data
-        pic->data = g_base64_decode (string, &pic->size);
+        /* Decode picture data. */
+        data = g_base64_decode (string, &data_size);
+        pic->bytes = g_bytes_new_take (data, data_size);
 
         if ( (string = vorbis_comment_query(vc,"COVERARTTYPE",field_num-1)) != NULL )
         {
@@ -521,7 +525,9 @@ et_add_file_tags_from_vorbis_comments (vorbis_comment *vc,
         Picture *pic;
         gsize bytes_pos, mimelen, desclen;
         guchar *decoded_ustr;
-        gsize decoded_len;
+        GBytes *bytes;
+        gsize decoded_size;
+        gsize data_size;
 
         pic = Picture_Allocate();
 
@@ -536,10 +542,9 @@ et_add_file_tags_from_vorbis_comments (vorbis_comment *vc,
 
         prev_pic = pic;
 
-        pic->data = NULL;
-
         /* Decode picture data. */
-        decoded_ustr = g_base64_decode (string, &decoded_len);
+        decoded_ustr = g_base64_decode (string, &decoded_size);
+        bytes = g_bytes_new_take (decoded_ustr, decoded_size);
 
         /* Reading picture type. */
         pic->type = read_guint32_from_byte (decoded_ustr, 0);
@@ -564,18 +569,14 @@ et_add_file_tags_from_vorbis_comments (vorbis_comment *vc,
         bytes_pos += desclen + 16;
 
         /* Reading picture size */
-        pic->size = read_guint32_from_byte (decoded_ustr, bytes_pos);
+        data_size = read_guint32_from_byte (decoded_ustr, bytes_pos);
         bytes_pos += 4;
 
-        /* Reading decoded picture */
-        pic->data = g_malloc (pic->size);
+        /* Read only the image data into a new GBytes. */
+        pic->bytes = g_bytes_new_from_bytes (bytes, bytes_pos, data_size);
 
-        for (i = 0; i < pic->size; i++)
-        {
-            pic->data [i] = decoded_ustr [i + bytes_pos];
-        }
-
-        g_free (decoded_ustr);
+        /* pic->bytes still holds a ref on the decoded data. */
+        g_bytes_unref (bytes);
     }
 
     /***************************
@@ -900,139 +901,142 @@ ogg_tag_write_file_tag (const ET_File *ETFile,
      **************/
     et_ogg_set_tag (vc, "ENCODED-BY=", FileTag->encoded_by, FALSE);
     
-    
     /***********
      * Picture *
      ***********/
     for (pic = FileTag->picture; pic != NULL; pic = pic->next)
     {
-        if (pic->data)
+        const gchar *mime;
+        guchar array[4];
+        guchar *ustring = NULL;
+        gsize ustring_len = 0;
+        gchar *base64_string;
+        gsize desclen;
+        gconstpointer data;
+        gsize data_size;
+        Picture_Format format = Picture_Format_From_Data (pic);
+
+        /* According to the specification, only PNG and JPEG images should
+         * be added to Vorbis comments. */
+        if (format != PICTURE_FORMAT_PNG && format != PICTURE_FORMAT_JPEG)
         {
-            const gchar *mime;
-            guchar array[4];
-            guchar *ustring = NULL;
-            gsize ustring_len = 0;
-            gchar *base64_string;
-            gsize desclen;
-            Picture_Format format = Picture_Format_From_Data (pic);
-
-            /* According to the specification, only PNG and JPEG images should
-             * be added to Vorbis comments. */
-            if (format != PICTURE_FORMAT_PNG && format != PICTURE_FORMAT_JPEG)
-            {
-                GdkPixbufLoader *loader;
-                GError *error = NULL;
+            GdkPixbufLoader *loader;
+            gconstpointer data;
+            gsize data_size;
+            GError *error = NULL;
 
-                loader = gdk_pixbuf_loader_new ();
+            loader = gdk_pixbuf_loader_new ();
+
+            data = g_bytes_get_data (pic->bytes, &data_size);
+
+            /* TODO: Use gdk_pixbuf_loader_write_bytes() */
+            if (!gdk_pixbuf_loader_write (loader, data, data_size, &error))
+            {
+                g_debug ("Error parsing image data: %s", error->message);
+                g_error_free (error);
+                g_object_unref (loader);
+                continue;
+            }
+            else
+            {
+                GdkPixbuf *pixbuf;
+                gchar *buffer;
+                gsize buffer_size;
 
-                if (!gdk_pixbuf_loader_write (loader, pic->data, pic->size,
-                                              &error))
+                if (!gdk_pixbuf_loader_close (loader, &error))
                 {
-                    g_debug ("Error parsing image data: %s", error->message);
+                    g_debug ("Error parsing image data: %s",
+                             error->message);
                     g_error_free (error);
                     g_object_unref (loader);
                     continue;
                 }
-                else
+
+                pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+
+                if (!pixbuf)
                 {
-                    GdkPixbuf *pixbuf;
-                    gchar *buffer;
-                    gsize buffer_size;
-
-                    if (!gdk_pixbuf_loader_close (loader, &error))
-                    {
-                        g_debug ("Error parsing image data: %s",
-                                 error->message);
-                        g_error_free (error);
-                        g_object_unref (loader);
-                        continue;
-                    }
-
-                    pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
-
-                    if (!pixbuf)
-                    {
-                        g_object_unref (loader);
-                        continue;
-                    }
-
-                    g_object_ref (pixbuf);
                     g_object_unref (loader);
+                    continue;
+                }
 
-                    /* Always convert to PNG. */
-                    if (!gdk_pixbuf_save_to_buffer (pixbuf, &buffer,
-                                                    &buffer_size, "png",
-                                                    &error, NULL))
-                    {
-                        g_debug ("Error while converting image to PNG: %s",
-                                 error->message);
-                        g_error_free (error);
-                        g_object_unref (pixbuf);
-                        continue;
-                    }
+                g_object_ref (pixbuf);
+                g_object_unref (loader);
 
+                /* Always convert to PNG. */
+                if (!gdk_pixbuf_save_to_buffer (pixbuf, &buffer,
+                                                &buffer_size, "png",
+                                                &error, NULL))
+                {
+                    g_debug ("Error while converting image to PNG: %s",
+                             error->message);
+                    g_error_free (error);
                     g_object_unref (pixbuf);
+                    continue;
+                }
 
-                    g_free (pic->data);
-                    pic->data = (guchar *)buffer;
-                    pic->size = buffer_size;
+                g_object_unref (pixbuf);
 
-                    /* Set the picture format to reflect the new data. */
-                    format = Picture_Format_From_Data (pic);
-                }
+                g_bytes_unref (pic->bytes);
+                pic->bytes = g_bytes_new_take (buffer, buffer_size);
+
+                /* Set the picture format to reflect the new data. */
+                format = Picture_Format_From_Data (pic);
             }
+        }
 
-            mime = Picture_Mime_Type_String (format);
+        mime = Picture_Mime_Type_String (format);
 
-            /* Calculating full length of byte string and allocating. */
-            desclen = pic->description ? strlen (pic->description) : 0;
-            ustring = g_malloc (4 * 8 + strlen (mime) + desclen + pic->size);
+        data = g_bytes_get_data (pic->bytes, &data_size);
 
-            /* Adding picture type. */
-            convert_to_byte_array (pic->type, array);
-            add_to_guchar_str (ustring, &ustring_len, array, 4);
+        /* Calculating full length of byte string and allocating. */
+        desclen = pic->description ? strlen (pic->description) : 0;
+        ustring = g_malloc (4 * 8 + strlen (mime) + desclen + data_size);
 
-            /* Adding MIME string and its length. */
-            convert_to_byte_array (strlen (mime), array);
-            add_to_guchar_str (ustring, &ustring_len, array, 4);
-            add_to_guchar_str (ustring, &ustring_len, (guchar *)mime,
-                               strlen (mime));
+        /* Adding picture type. */
+        convert_to_byte_array (pic->type, array);
+        add_to_guchar_str (ustring, &ustring_len, array, 4);
 
-            /* Adding picture description. */
-            convert_to_byte_array (desclen, array);
-            add_to_guchar_str (ustring, &ustring_len, array, 4);
-            add_to_guchar_str (ustring, &ustring_len,
-                               (guchar *)pic->description,
-                               desclen);
+        /* Adding MIME string and its length. */
+        convert_to_byte_array (strlen (mime), array);
+        add_to_guchar_str (ustring, &ustring_len, array, 4);
+        add_to_guchar_str (ustring, &ustring_len, (guchar *)mime,
+                           strlen (mime));
 
-            /* Adding width, height, color depth, indexed colors. */
-            convert_to_byte_array (pic->width, array);
-            add_to_guchar_str (ustring, &ustring_len, array, 4);
+        /* Adding picture description. */
+        convert_to_byte_array (desclen, array);
+        add_to_guchar_str (ustring, &ustring_len, array, 4);
+        add_to_guchar_str (ustring, &ustring_len,
+                           (guchar *)pic->description,
+                           desclen);
 
-            convert_to_byte_array (pic->height, array);
-            add_to_guchar_str (ustring, &ustring_len, array, 4);
+        /* Adding width, height, color depth, indexed colors. */
+        convert_to_byte_array (pic->width, array);
+        add_to_guchar_str (ustring, &ustring_len, array, 4);
 
-            convert_to_byte_array (0, array);
-            add_to_guchar_str (ustring, &ustring_len, array, 4);
+        convert_to_byte_array (pic->height, array);
+        add_to_guchar_str (ustring, &ustring_len, array, 4);
 
-            convert_to_byte_array (0, array);
-            add_to_guchar_str (ustring, &ustring_len, array, 4);
+        convert_to_byte_array (0, array);
+        add_to_guchar_str (ustring, &ustring_len, array, 4);
 
-            /* Adding picture data and its size. */
-            convert_to_byte_array (pic->size, array);
-            add_to_guchar_str (ustring, &ustring_len, array, 4);
+        convert_to_byte_array (0, array);
+        add_to_guchar_str (ustring, &ustring_len, array, 4);
 
-            add_to_guchar_str (ustring, &ustring_len, pic->data, pic->size);
+        /* Adding picture data and its size. */
+        convert_to_byte_array (data_size, array);
+        add_to_guchar_str (ustring, &ustring_len, array, 4);
 
-            base64_string = g_base64_encode (ustring, ustring_len);
-            string = g_strconcat ("METADATA_BLOCK_PICTURE=", base64_string,
-                                  NULL);
-            vorbis_comment_add (vc, string);
+        add_to_guchar_str (ustring, &ustring_len, data, data_size);
 
-            g_free (base64_string);
-            g_free (ustring);
-            g_free (string);
-        }
+        base64_string = g_base64_encode (ustring, ustring_len);
+        string = g_strconcat ("METADATA_BLOCK_PICTURE=", base64_string,
+                              NULL);
+        vorbis_comment_add (vc, string);
+
+        g_free (base64_string);
+        g_free (ustring);
+        g_free (string);
     }
 
     /**************************
diff --git a/tests/test-picture.c b/tests/test-picture.c
index a1970d1..adcb7d6 100644
--- a/tests/test-picture.c
+++ b/tests/test-picture.c
@@ -34,8 +34,7 @@ picture_copy (void)
     pic1->width = 640;
     pic1->height = 480;
     pic1->description = g_strdup ("foobar.png");
-    pic1->size = 10;
-    pic1->data = g_malloc0 (pic1->size);
+    pic1->bytes = g_bytes_new_static ("foobar", 6);
 
     pic2 = Picture_Copy (pic1);
 
@@ -43,7 +42,9 @@ picture_copy (void)
     g_assert_cmpint (pic2->width, ==, 640);
     g_assert_cmpint (pic2->height, ==, 480);
     g_assert_cmpstr (pic2->description, ==, "foobar.png");
-    g_assert_cmpint (pic2->size, ==, 10);
+    g_assert_cmpint (g_bytes_hash (pic2->bytes), ==,
+                     g_bytes_hash (pic1->bytes));
+    g_assert (pic2->bytes == pic1->bytes);
     g_assert (pic2->next == NULL);
 
     pic3 = Picture_Allocate ();
@@ -52,8 +53,7 @@ picture_copy (void)
     pic3->width = 320;
     pic3->height = 240;
     pic3->description = g_strdup ("bash.jpg");
-    pic3->size = 20;
-    pic3->data = g_malloc0 (pic3->size);
+    pic3->bytes = g_bytes_new_static ("foo", 3);
 
     pic1->next = pic2;
     pic2->next = pic3;
@@ -64,7 +64,7 @@ picture_copy (void)
     g_assert_cmpint (pic2_copy->width, ==, 640);
     g_assert_cmpint (pic2_copy->height, ==, 480);
     g_assert_cmpstr (pic2_copy->description, ==, "foobar.png");
-    g_assert_cmpint (pic2_copy->size, ==, 10);
+    g_assert_cmpint (g_bytes_get_size (pic2_copy->bytes), ==, 6);
     g_assert (pic2_copy->next == NULL);
 
     pic1_copy = Picture_Copy (pic1);
@@ -79,7 +79,7 @@ picture_copy (void)
     g_assert_cmpint (pic3_copy->width, ==, 320);
     g_assert_cmpint (pic3_copy->height, ==, 240);
     g_assert_cmpstr (pic3_copy->description, ==, "bash.jpg");
-    g_assert_cmpint (pic3_copy->size, ==, 20);
+    g_assert_cmpint (g_bytes_get_size (pic3_copy->bytes), ==, 3);
 
     Picture_Free (pic1_copy);
     Picture_Free (pic2_copy);


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