[easytag/wip/dsf-support: 7/10] Write ID3v2.3 tags to DSF files
- From: David King <davidk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [easytag/wip/dsf-support: 7/10] Write ID3v2.3 tags to DSF files
- Date: Mon, 24 Nov 2014 21:52:28 +0000 (UTC)
commit 784608c45b8012a55d36ac73b00c1996569d87b3
Author: David King <amigadave amigadave com>
Date: Thu Nov 13 16:59:45 2014 +0000
Write ID3v2.3 tags to DSF files
https://bugzilla.gnome.org/show_bug.cgi?id=708368
src/tags/dsf_tag.c | 484 +++++++++++++++++++++++++++++------------
src/tags/id3_tag.c | 235 ++++++++++-----------
src/tags/id3_tag.h | 6 +
src/tags/id3lib/c_wrapper.cpp | 24 ++
src/tags/id3lib/id3_bugfix.h | 2 +
5 files changed, 491 insertions(+), 260 deletions(-)
---
diff --git a/src/tags/dsf_tag.c b/src/tags/dsf_tag.c
index d9ac7eb..1a80b1e 100644
--- a/src/tags/dsf_tag.c
+++ b/src/tags/dsf_tag.c
@@ -34,6 +34,11 @@
#include <id3tag.h>
#include "id3_tag.h"
+#ifdef ENABLE_ID3LIB
+#include <id3.h>
+#include "id3lib/id3_bugfix.h"
+#endif
+
#define DSF_METADATA_CHUNK_OFFSET 20
/*
@@ -189,7 +194,6 @@ et_dsf_tag_read_file_tag (GFile *file,
unsigned version = id3_tag_version (tag);
#ifdef ENABLE_ID3LIB
-#if 0 /* Disable tag downgrading from 2.4 until id3lib render is supported. */
/* Besides upgrading old tags, downgrade ID3v2.4 to ID3v2.3 */
if (g_settings_get_boolean (MainSettings, "id3v2-version-4"))
{
@@ -201,7 +205,6 @@ et_dsf_tag_read_file_tag (GFile *file,
| (ID3_TAG_VERSION_MAJOR (version) == 4));
}
#else
-#endif
update = (ID3_TAG_VERSION_MAJOR (version) < 4);
#endif
}
@@ -238,6 +241,325 @@ err:
return FALSE;
}
+#ifdef ENABLE_ID3LIB
+
+static gboolean
+et_dsf_tag_write_id3v23 (const File_Tag *FileTag,
+ const guchar *id3_buffer,
+ long tagsize,
+ GOutputStream *ostream,
+ GError **error)
+{
+ GSeekable *seekable;
+ goffset id3_offset;
+ ID3Tag *tag;
+ gboolean strip_tags = TRUE;
+ size_t new_tagsize;
+ guchar *new_tag_buffer;
+ gsize bytes_written;
+
+ /* TODO: Call id3tag_check_if_id3lib_is_buggy(). */
+
+ seekable = G_SEEKABLE (ostream);
+ /* Offset of the ID3v2 tag is at the current stream position. */
+ id3_offset = g_seekable_tell (seekable);
+
+ if ((tag = ID3Tag_New ()) == NULL)
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOMEM, "%s",
+ g_strerror (ENOMEM));
+ goto err;
+ }
+
+ /* Copy the header out to a separate buffer, as id3lib expects the header
+ * and remainder of the tag to be processed separately. */
+ if (tagsize > ID3_TAGHEADERSIZE)
+ {
+ const guchar id3_header[ID3_TAGHEADERSIZE];
+ ID3_Err id3_err;
+
+ memcpy (&id3_header, id3_buffer, ID3_TAGHEADERSIZE);
+
+ if ((id3_err = ID3Tag_Parse (tag, id3_header,
+ &id3_buffer[ID3_TAGHEADERSIZE]))
+ != ID3E_NoError)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ Id3tag_Get_Error_Message (id3_err));
+ ID3Tag_Delete (tag);
+ goto err;
+ }
+ }
+
+ ID3Tag_SetPadding (tag, TRUE);
+
+ /* Fill the tag with the new values. */
+ et_id3tag_set_id3tag_from_file_tag (FileTag, tag, &strip_tags);
+
+ /* Truncate the file and update the metadata offset if the tags should be
+ * stripped. */
+ if (strip_tags)
+ {
+ guchar metadata_offset[8] = { 0, };
+
+ ID3Tag_Delete (tag);
+
+ if (!g_seekable_can_truncate (seekable))
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_BADF, "%s",
+ g_strerror (EBADF));
+ goto err;
+ }
+
+ if (!g_seekable_truncate (seekable, id3_offset, NULL, error))
+ {
+ goto err;
+ }
+
+ if (!g_seekable_seek (seekable, DSF_METADATA_CHUNK_OFFSET, G_SEEK_SET,
+ NULL, error))
+ {
+ goto err;
+ }
+
+ if (!g_output_stream_write_all (ostream, metadata_offset, 8,
+ &bytes_written, NULL, error))
+ {
+ goto err;
+ }
+ else if (bytes_written != 8)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ _("Error writing tags to file"));
+ goto err;
+ }
+
+ return TRUE;
+ }
+
+ new_tagsize = ID3Tag_Size (tag);
+
+ /* FIXME: This is probably a bug in id3lib, as a size of 0 should only be
+ * returned if there are no valid frames, and frames were added earlier in
+ * et_id3tag_set_id3tag_from_file_tag(). */
+ if (new_tagsize == 0)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ _("Error writing tags to file"));
+ ID3Tag_Delete (tag);
+ goto err;
+ }
+
+ /* FIXME: The return vlaue of ID3Tag_Size() should include the header and
+ * tag size, so this looks like an overallocation. However, Valgrind
+ * complains about reading into unallocated memory otherwise. */
+ new_tag_buffer = g_malloc0 (new_tagsize + ID3_TAGHEADERSIZE);
+ /* The call to ID3Tag_Size() gives an overestimate, but ID3Tag_Render()
+ * returns the real size of the tag. */
+ new_tagsize = ID3Tag_Render (tag, new_tag_buffer, ID3TT_ID3V2);
+
+ ID3Tag_Delete (tag);
+
+ /* Only truncate the file if the new tag is smaller than the old one. */
+ if (new_tagsize < tagsize)
+ {
+ if (!g_seekable_can_truncate (seekable))
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_BADF, "%s",
+ g_strerror (EBADF));
+ g_free (new_tag_buffer);
+ goto err;
+ }
+
+ if (!g_seekable_truncate (seekable, id3_offset + new_tagsize, NULL,
+ error))
+ {
+ g_free (new_tag_buffer);
+ goto err;
+ }
+ }
+
+ if (!g_output_stream_write_all (ostream, new_tag_buffer, new_tagsize,
+ &bytes_written, NULL, error))
+ {
+ g_free (new_tag_buffer);
+ goto err;
+ }
+ else if (bytes_written != new_tagsize)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ _("Error writing tags to file"));
+ g_free (new_tag_buffer);
+ goto err;
+ }
+
+ g_free (new_tag_buffer);
+ return TRUE;
+
+err:
+ return FALSE;
+}
+
+#endif
+
+static gboolean
+et_dsf_tag_write_id3v24 (const File_Tag *FileTag,
+ const guchar *id3_buffer,
+ long tagsize,
+ GOutputStream *ostream,
+ GError **error)
+{
+ struct id3_tag *tag;
+ GSeekable *seekable;
+ gboolean strip_tags = TRUE;
+ gsize bytes_written;
+ guchar *new_tag_buffer;
+ long new_tagsize;
+ goffset id3_offset;
+
+ if (tagsize == 0)
+ {
+ /* No ID3v2 tag. */
+ tag = id3_tag_new ();
+ }
+ else
+ {
+ /* Create an empty tag if there was a problem reading the existing
+ * tag. */
+ if (!(tag = id3_tag_parse ((id3_byte_t const *)id3_buffer, tagsize)))
+ {
+ tag = id3_tag_new ();
+ }
+ }
+
+ seekable = G_SEEKABLE (ostream);
+ /* Offset of the ID3v2 tag is at the current stream position. */
+ id3_offset = g_seekable_tell (seekable);
+
+ /* Set padding. */
+ if ((tag->paddedsize < 1024) || ((tag->paddedsize > 4096)
+ && (tagsize < 1024)))
+ {
+ tag->paddedsize = 1024;
+ }
+
+ /* Set options. */
+ id3_tag_options (tag, ID3_TAG_OPTION_UNSYNCHRONISATION
+ | ID3_TAG_OPTION_APPENDEDTAG
+ | ID3_TAG_OPTION_ID3V1
+ | ID3_TAG_OPTION_CRC
+ | ID3_TAG_OPTION_COMPRESSION,
+ 0);
+
+ if (g_settings_get_boolean (MainSettings, "id3v2-crc32"))
+ {
+ id3_tag_options (tag, ID3_TAG_OPTION_CRC, ~0);
+ }
+
+ if (g_settings_get_boolean (MainSettings, "id3v2-compression"))
+ {
+ id3_tag_options (tag, ID3_TAG_OPTION_COMPRESSION, ~0);
+ }
+
+ /* Only set the IDv2 tag. */
+ et_id3tag_set_id3_tag_from_file_tag (FileTag, NULL, tag, &strip_tags);
+
+ /* Truncate the file and update the metadata offset if the tags should be
+ * stripped. */
+ if (strip_tags)
+ {
+ guchar metadata_offset[8] = { 0, };
+
+ id3_tag_delete (tag);
+
+ if (!g_seekable_can_truncate (seekable))
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_BADF, "%s",
+ g_strerror (EBADF));
+ goto err;
+ }
+
+ if (!g_seekable_truncate (seekable, id3_offset, NULL, error))
+ {
+ goto err;
+ }
+
+ if (!g_seekable_seek (seekable, DSF_METADATA_CHUNK_OFFSET, G_SEEK_SET,
+ NULL, error))
+ {
+ goto err;
+ }
+
+ if (!g_output_stream_write_all (ostream, metadata_offset, 8,
+ &bytes_written, NULL, error))
+ {
+ goto err;
+ }
+ else if (bytes_written != 8)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ _("Error writing tags to file"));
+ goto err;
+ }
+
+ return TRUE;
+ }
+
+ new_tagsize = id3_tag_render (tag, NULL);
+ new_tag_buffer = g_malloc (new_tagsize);
+
+ if ((new_tagsize = id3_tag_render (tag, new_tag_buffer)) == 0)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ _("Error writing tags to file"));
+ id3_tag_delete (tag);
+ g_free (new_tag_buffer);
+ goto err;
+ }
+
+ id3_tag_delete (tag);
+
+ /* Only truncate the file if the new tag is smaller than the old one. */
+ if (new_tagsize < tagsize)
+ {
+ if (!g_seekable_can_truncate (seekable))
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_BADF, "%s",
+ g_strerror (EBADF));
+ g_free (new_tag_buffer);
+ goto err;
+ }
+
+ if (!g_seekable_truncate (seekable, id3_offset + new_tagsize, NULL,
+ error))
+ {
+ g_free (new_tag_buffer);
+ goto err;
+ }
+ }
+
+ if (!g_output_stream_write_all (ostream, new_tag_buffer, new_tagsize,
+ &bytes_written, NULL, error))
+ {
+ g_free (new_tag_buffer);
+ goto err;
+ }
+ else if (bytes_written != new_tagsize)
+ {
+ g_free (new_tag_buffer);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ _("Error writing tags to file"));
+ goto err;
+ }
+
+ g_free (new_tag_buffer);
+
+ return TRUE;
+
+err:
+ return FALSE;
+}
+
gboolean
et_dsf_tag_write_file_tag (const ET_File *ETFile,
GError **error)
@@ -256,13 +578,9 @@ et_dsf_tag_write_file_tag (const ET_File *ETFile,
guint64 id3_offset;
GSeekable *seekable;
guchar id3_query[ID3_TAG_QUERYSIZE];
+ guchar *id3_buffer;
long tagsize;
goffset eos_offset;
- struct id3_tag *tag;
- gboolean strip_tags = TRUE;
- long new_tagsize;
- guchar *new_tag_buffer;
- gsize bytes_written;
g_return_val_if_fail (ETFile != NULL && ETFile->FileTag != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -274,7 +592,7 @@ et_dsf_tag_write_file_tag (const ET_File *ETFile,
iostream = g_file_open_readwrite (file, NULL, error);
g_object_unref (file);
- if (iostream == NULL)
+ if (!iostream)
{
return FALSE;
}
@@ -290,14 +608,14 @@ et_dsf_tag_write_file_tag (const ET_File *ETFile,
goto err;
}
- if (memcmp (&header, DSF_HEADER_MAGIC, 4) != 0)
+ if (memcmp (&header, "DSD ", 4) != 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
_("Not a DSF file"));
goto err;
}
- if (memcmp (&header[28], DSF_HEADER_FORMAT_MAGIC, 4) != 0)
+ if (memcmp (&header[28], "fmt ", 4) != 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
_("Not a DSF file"));
@@ -349,15 +667,14 @@ et_dsf_tag_write_file_tag (const ET_File *ETFile,
{
/* No ID3v2 tag. */
id3_offset = file_size;
-
- tag = id3_tag_new ();
+ id3_buffer = NULL;
tagsize = 0;
}
else
{
- guchar *id3_buffer;
- /* Read existing ID3v2 tag. */
+ /* Read in the existing ID3v2 tag, using libid3tag to determine the
+ * size. */
/* Seek to the start of the metadata chunk. */
if (!g_seekable_seek (seekable, id3_offset, G_SEEK_SET, NULL, error))
@@ -385,7 +702,9 @@ et_dsf_tag_write_file_tag (const ET_File *ETFile,
goto err;
}
- id3_buffer = g_malloc (tagsize);
+ /* FIXME: id3lib seems to read past the end of a buffer that is exactly
+ * the right size, so over-allocate. */
+ id3_buffer = g_malloc0 (tagsize + ID3_TAG_QUERYSIZE);
/* Copy the query buffer. */
memcpy (id3_buffer, id3_query, ID3_TAG_QUERYSIZE);
@@ -403,17 +722,6 @@ et_dsf_tag_write_file_tag (const ET_File *ETFile,
g_free (id3_buffer);
goto err;
}
-
- /* Create an empty tag if there was a problem reading the existing
- * tag. */
- if (!(tag = id3_tag_parse ((id3_byte_t const *)id3_buffer, tagsize)))
- {
- tag = id3_tag_new ();
- }
-
- g_free (id3_buffer);
-
- /* TODO: Check for an empty tag? */
}
/* No reading from this point forward. */
@@ -422,133 +730,37 @@ et_dsf_tag_write_file_tag (const ET_File *ETFile,
ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
seekable = G_SEEKABLE (ostream);
- /* Set padding. */
- if ((tag->paddedsize < 1024) || ((tag->paddedsize > 4096)
- && (tagsize < 1024)))
- {
- tag->paddedsize = 1024;
- }
-
- /* Set options. */
- id3_tag_options (tag, ID3_TAG_OPTION_UNSYNCHRONISATION
- | ID3_TAG_OPTION_APPENDEDTAG
- | ID3_TAG_OPTION_ID3V1
- | ID3_TAG_OPTION_CRC
- | ID3_TAG_OPTION_COMPRESSION,
- 0);
-
- if (g_settings_get_boolean (MainSettings, "id3v2-crc32"))
- {
- id3_tag_options (tag, ID3_TAG_OPTION_CRC, ~0);
- }
-
- if (g_settings_get_boolean (MainSettings, "id3v2-compression"))
- {
- id3_tag_options (tag, ID3_TAG_OPTION_COMPRESSION, ~0);
- }
-
/* Seek to the start of the metadata chunk. */
if (!g_seekable_seek (seekable, id3_offset, G_SEEK_SET, NULL, error))
{
+ g_free (id3_buffer);
goto err;
}
- /* Only set the IDv2 tag. */
- et_id3tag_set_id3_tag_from_file_tag (FileTag, NULL, tag, &strip_tags);
-
- /* FIXME; For ID3v2.3 support, add ID3Tag_Render() to id3lib c_wrapper.cpp:
- * http://sourceforge.net/p/id3lib/patches/75/ */
-
- /* Truncate the file and update the metadata offset if the tags should be
- * stripped. */
- if (strip_tags)
+#ifdef ENABLE_ID3LIB
+ if (g_settings_get_boolean (MainSettings, "id3v2-version-4"))
{
- guchar metadata_offset[8] = { 0, };
-
- id3_tag_delete (tag);
-
- if (!g_seekable_can_truncate (seekable))
- {
- g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_BADF, "%s",
- g_strerror (EBADF));
- goto err;
- }
-
- if (!g_seekable_truncate (seekable, id3_offset, NULL, error))
- {
- goto err;
- }
-
- if (!g_seekable_seek (seekable, DSF_METADATA_CHUNK_OFFSET, G_SEEK_SET,
- NULL, error))
- {
- goto err;
- }
-
- if (!g_output_stream_write_all (ostream, metadata_offset, 8,
- &bytes_written, NULL, error))
- {
- goto err;
- }
- else if (bytes_written != 8)
+#endif
+ if (!et_dsf_tag_write_id3v24 (FileTag, id3_buffer, tagsize, ostream,
+ error))
{
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
- _("Error writing tags to file"));
+ g_free (id3_buffer);
goto err;
}
-
- g_object_unref (iostream);
- return TRUE;
- }
-
- new_tagsize = id3_tag_render (tag, NULL);
- new_tag_buffer = g_malloc (new_tagsize);
-
- if ((new_tagsize = id3_tag_render (tag, new_tag_buffer)) == 0)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
- _("Error writing tags to file"));
- id3_tag_delete (tag);
- g_free (new_tag_buffer);
- goto err;
+#ifdef ENABLE_ID3LIB
}
-
- id3_tag_delete (tag);
-
- /* Only truncate the file if the new tag is smaller than the old one. */
- if (new_tagsize < tagsize)
+ else
{
- if (!g_seekable_can_truncate (seekable))
- {
- g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_BADF, "%s",
- g_strerror (EBADF));
- g_free (new_tag_buffer);
- goto err;
- }
-
- if (!g_seekable_truncate (seekable, id3_offset + new_tagsize, NULL,
- error))
+ if (!et_dsf_tag_write_id3v23 (FileTag, id3_buffer, tagsize, ostream,
+ error))
{
- g_free (new_tag_buffer);
+ g_free (id3_buffer);
goto err;
}
}
+#endif
- if (!g_output_stream_write_all (ostream, new_tag_buffer, new_tagsize,
- &bytes_written, NULL, error))
- {
- g_free (new_tag_buffer);
- goto err;
- }
- else if (bytes_written != new_tagsize)
- {
- g_free (new_tag_buffer);
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
- _("Error writing tags to file"));
- goto err;
- }
-
- g_free (new_tag_buffer);
+ g_free (id3_buffer);
eos_offset = g_seekable_tell (seekable);
diff --git a/src/tags/id3_tag.c b/src/tags/id3_tag.c
index a61f938..11191dc 100644
--- a/src/tags/id3_tag.c
+++ b/src/tags/id3_tag.c
@@ -57,7 +57,6 @@
/**************
* Prototypes *
**************/
-static gchar *Id3tag_Get_Error_Message (ID3_Err error);
static void Id3tag_Prepare_ID3v1 (ID3Tag *id3_tag);
static gchar *Id3tag_Rules_For_ISO_Fields (const gchar *string,
const gchar *from_codeset,
@@ -130,114 +129,16 @@ et_id3tag_get_tpos_from_file_tag (const File_Tag *FileTag)
return g_string_free (gstring, FALSE);
}
-/*
- * Write the ID3 tags to the file. Returns TRUE on success, else 0.
- */
-static gboolean
-id3tag_write_file_v23tag (const ET_File *ETFile,
- GError **error)
+void
+et_id3tag_set_id3tag_from_file_tag (const File_Tag *FileTag,
+ ID3Tag *id3_tag,
+ gboolean *strip_tags)
{
- const File_Tag *FileTag;
- const gchar *filename;
- const gchar *filename_utf8;
- gchar *basename_utf8;
- GFile *file;
- ID3Tag *id3_tag = NULL;
- ID3_Err error_strip_id3v1 = ID3E_NoError;
- ID3_Err error_strip_id3v2 = ID3E_NoError;
- ID3_Err error_update_id3v1 = ID3E_NoError;
- ID3_Err error_update_id3v2 = ID3E_NoError;
- gboolean success = TRUE;
- gint number_of_frames;
- gboolean has_title = FALSE;
- gboolean has_artist = FALSE;
- gboolean has_album_artist= FALSE;
- gboolean has_album = FALSE;
- gboolean has_disc_number = FALSE;
- gboolean has_year = FALSE;
- gboolean has_track = FALSE;
- gboolean has_genre = FALSE;
- gboolean has_comment = FALSE;
- gboolean has_composer = FALSE;
- gboolean has_orig_artist = FALSE;
- gboolean has_copyright = FALSE;
- gboolean has_url = FALSE;
- gboolean has_encoded_by = FALSE;
- gboolean has_picture = FALSE;
- //gboolean has_song_len = FALSE;
- static gboolean flag_first_check = TRUE;
- static gboolean flag_id3lib_bugged = TRUE;
-
ID3Frame *id3_frame;
ID3Field *id3_field;
- //gchar *string;
gchar *string1;
Picture *pic;
- g_return_val_if_fail (ETFile != NULL && ETFile->FileTag != NULL, FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
- // When writing the first MP3 file, we check if the version of id3lib of the
- // system doesn't contain a bug when writting Unicode tags
- if (flag_first_check
- && g_settings_get_boolean (MainSettings, "id3v2-enable-unicode"))
- {
- flag_first_check = FALSE;
- flag_id3lib_bugged = id3tag_check_if_id3lib_is_buggy (NULL);
- }
-
- FileTag = (File_Tag *)ETFile->FileTag->data;
- filename = ((File_Name *)ETFile->FileNameCur->data)->value;
- filename_utf8 = ((File_Name *)ETFile->FileNameCur->data)->value_utf8;
-
- file = g_file_new_for_path (filename);
-
- /* FIXME: Handle this in the caller instead. */
- /* This is a protection against a bug in id3lib that enters an infinite
- * loop with corrupted MP3 files (files containing only zeroes) */
- if (et_id3tag_check_if_file_is_corrupted (file, error))
- {
- GtkWidget *msgdialog;
- gchar *basename;
- gchar *basename_utf8;
-
- basename = g_file_get_basename (file);
- basename_utf8 = filename_to_display (basename);
-
- msgdialog = gtk_message_dialog_new (GTK_WINDOW (MainWindow),
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE,
- _("As the following corrupted file ā%sā will cause an error in
id3lib, it will not be processed"),
- basename_utf8);
- gtk_window_set_title (GTK_WINDOW (msgdialog), _("Corrupted file"));
-
- gtk_dialog_run (GTK_DIALOG (msgdialog));
- gtk_widget_destroy (msgdialog);
- g_free (basename);
- g_free (basename_utf8);
- g_object_unref (file);
- return FALSE;
- }
-
- /* We get again the tag from the file to keep also unused data (by EasyTAG), then
- * we replace the changed data */
- if ((id3_tag = ID3Tag_New ()) == NULL)
- {
- g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOMEM, "%s",
- g_strerror (ENOMEM));
- g_object_unref (file);
- return FALSE;
- }
-
- basename_utf8 = g_path_get_basename(filename_utf8);
-
- ID3Tag_Link(id3_tag,filename);
-
- /* Set padding when tag was changed, for faster writing */
- ID3Tag_SetPadding(id3_tag,TRUE);
-
-
/*********
* Title *
*********/
@@ -250,7 +151,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
id3_frame = ID3Frame_NewID(ID3FID_TITLE);
ID3Tag_AttachFrame(id3_tag,id3_frame);
Id3tag_Set_Field(id3_frame, ID3FN_TEXT, FileTag->title);
- has_title = TRUE;
+ *strip_tags = FALSE;
}
@@ -264,7 +165,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
id3_frame = ID3Frame_NewID(ID3FID_LEADARTIST);
ID3Tag_AttachFrame(id3_tag,id3_frame);
Id3tag_Set_Field(id3_frame, ID3FN_TEXT, FileTag->artist);
- has_artist = TRUE;
+ *strip_tags = FALSE;
}
/****************
@@ -277,7 +178,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
id3_frame = ID3Frame_NewID(ID3FID_BAND);
ID3Tag_AttachFrame(id3_tag,id3_frame);
Id3tag_Set_Field(id3_frame, ID3FN_TEXT, FileTag->album_artist);
- has_album_artist = TRUE;
+ *strip_tags = FALSE;
}
/*********
@@ -290,7 +191,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
id3_frame = ID3Frame_NewID(ID3FID_ALBUM);
ID3Tag_AttachFrame(id3_tag,id3_frame);
Id3tag_Set_Field(id3_frame, ID3FN_TEXT, FileTag->album);
- has_album = TRUE;
+ *strip_tags = FALSE;
}
@@ -306,7 +207,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
string1 = et_id3tag_get_tpos_from_file_tag (FileTag);
Id3tag_Set_Field (id3_frame, ID3FN_TEXT, string1);
g_free (string1);
- has_disc_number = TRUE;
+ *strip_tags = FALSE;
}
@@ -320,7 +221,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
id3_frame = ID3Frame_NewID(ID3FID_YEAR);
ID3Tag_AttachFrame(id3_tag,id3_frame);
Id3tag_Set_Field(id3_frame, ID3FN_TEXT, FileTag->year);
- has_year = TRUE;
+ *strip_tags = FALSE;
}
@@ -341,7 +242,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
Id3tag_Set_Field(id3_frame, ID3FN_TEXT, string1);
g_free(string1);
- has_track = TRUE;
+ *strip_tags = FALSE;
}
@@ -376,7 +277,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
Id3tag_Set_Field(id3_frame, ID3FN_TEXT, genre_string_tmp);
g_free(genre_string_tmp);
- has_genre = TRUE;
+ *strip_tags = FALSE;
}
@@ -394,7 +295,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
// Disabled as when using unicode, the comment field stay in ISO.
//Id3tag_Set_Field(id3_frame, ID3FN_DESCRIPTION, "ID3v1 Comment");
//Id3tag_Set_Field(id3_frame, ID3FN_LANGUAGE, "XXX");
- has_comment = TRUE;
+ *strip_tags = FALSE;
}
@@ -408,7 +309,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
id3_frame = ID3Frame_NewID(ID3FID_COMPOSER);
ID3Tag_AttachFrame(id3_tag,id3_frame);
Id3tag_Set_Field(id3_frame, ID3FN_TEXT, FileTag->composer);
- has_composer = TRUE;
+ *strip_tags = FALSE;
}
@@ -422,7 +323,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
id3_frame = ID3Frame_NewID(ID3FID_ORIGARTIST);
ID3Tag_AttachFrame(id3_tag,id3_frame);
Id3tag_Set_Field(id3_frame, ID3FN_TEXT, FileTag->orig_artist);
- has_orig_artist = TRUE;
+ *strip_tags = FALSE;
}
@@ -436,7 +337,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
id3_frame = ID3Frame_NewID(ID3FID_COPYRIGHT);
ID3Tag_AttachFrame(id3_tag,id3_frame);
Id3tag_Set_Field(id3_frame, ID3FN_TEXT, FileTag->copyright);
- has_copyright = TRUE;
+ *strip_tags = FALSE;
}
@@ -450,7 +351,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
id3_frame = ID3Frame_NewID(ID3FID_WWWUSER);
ID3Tag_AttachFrame(id3_tag,id3_frame);
Id3tag_Set_Field(id3_frame, ID3FN_URL, FileTag->url);
- has_composer = TRUE;
+ *strip_tags = FALSE;
}
@@ -464,7 +365,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
id3_frame = ID3Frame_NewID(ID3FID_ENCODEDBY);
ID3Tag_AttachFrame(id3_tag,id3_frame);
Id3tag_Set_Field(id3_frame, ID3FN_TEXT, FileTag->encoded_by);
- has_encoded_by = TRUE;
+ *strip_tags = FALSE;
}
@@ -474,8 +375,6 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
while ( (id3_frame = ID3Tag_FindFrameWithID(id3_tag,ID3FID_PICTURE)) )
ID3Tag_RemoveFrame(id3_tag,id3_frame);
- has_picture = FALSE;
-
for (pic = FileTag->picture; pic != NULL; pic = pic->next)
{
Picture_Format format = Picture_Format_From_Data(pic);
@@ -527,7 +426,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
if ((id3_field = ID3Frame_GetField(id3_frame,ID3FN_DATA)))
ID3Field_SetBINARY(id3_field, pic->data, pic->size);
- has_picture = TRUE;
+ *strip_tags = FALSE;
}
@@ -549,7 +448,96 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
g_free(string);
has_song_len = TRUE;
}*/
+}
+/*
+ * Write the ID3 tags to the file. Returns TRUE on success, else 0.
+ */
+static gboolean
+id3tag_write_file_v23tag (const ET_File *ETFile,
+ GError **error)
+{
+ const File_Tag *FileTag;
+ const gchar *filename;
+ const gchar *filename_utf8;
+ gchar *basename_utf8;
+ GFile *file;
+ ID3Tag *id3_tag = NULL;
+ ID3_Err error_strip_id3v1 = ID3E_NoError;
+ ID3_Err error_strip_id3v2 = ID3E_NoError;
+ ID3_Err error_update_id3v1 = ID3E_NoError;
+ ID3_Err error_update_id3v2 = ID3E_NoError;
+ gboolean success = TRUE;
+ gint number_of_frames;
+ gboolean strip_tags = TRUE;
+ //gboolean has_song_len = FALSE;
+ static gboolean flag_first_check = TRUE;
+ static gboolean flag_id3lib_bugged = TRUE;
+
+ g_return_val_if_fail (ETFile != NULL && ETFile->FileTag != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ // When writing the first MP3 file, we check if the version of id3lib of the
+ // system doesn't contain a bug when writting Unicode tags
+ if (flag_first_check
+ && g_settings_get_boolean (MainSettings, "id3v2-enable-unicode"))
+ {
+ flag_first_check = FALSE;
+ flag_id3lib_bugged = id3tag_check_if_id3lib_is_buggy (NULL);
+ }
+
+ FileTag = (File_Tag *)ETFile->FileTag->data;
+ filename = ((File_Name *)ETFile->FileNameCur->data)->value;
+ filename_utf8 = ((File_Name *)ETFile->FileNameCur->data)->value_utf8;
+
+ file = g_file_new_for_path (filename);
+
+ /* FIXME: Handle this in the caller instead. */
+ /* This is a protection against a bug in id3lib that enters an infinite
+ * loop with corrupted MP3 files (files containing only zeroes) */
+ if (et_id3tag_check_if_file_is_corrupted (file, error))
+ {
+ GtkWidget *msgdialog;
+ gchar *basename;
+ gchar *basename_utf8;
+
+ basename = g_file_get_basename (file);
+ basename_utf8 = filename_to_display (basename);
+
+ msgdialog = gtk_message_dialog_new (GTK_WINDOW (MainWindow),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("As the following corrupted file ā%sā will cause an error in
id3lib, it will not be processed"),
+ basename_utf8);
+ gtk_window_set_title (GTK_WINDOW (msgdialog), _("Corrupted file"));
+
+ gtk_dialog_run (GTK_DIALOG (msgdialog));
+ gtk_widget_destroy (msgdialog);
+ g_free (basename);
+ g_free (basename_utf8);
+ g_object_unref (file);
+ return FALSE;
+ }
+
+ /* We get again the tag from the file to keep also unused data (by EasyTAG), then
+ * we replace the changed data */
+ if ((id3_tag = ID3Tag_New ()) == NULL)
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOMEM, "%s",
+ g_strerror (ENOMEM));
+ g_object_unref (file);
+ return FALSE;
+ }
+
+ basename_utf8 = g_path_get_basename(filename_utf8);
+
+ ID3Tag_Link(id3_tag,filename);
+
+ /* Set padding when tag was changed, for faster writing */
+ ID3Tag_SetPadding(id3_tag,TRUE);
+
+ et_id3tag_set_id3tag_from_file_tag (FileTag, id3_tag, &strip_tags);
/******************************
* Delete an APE tag if found *
@@ -583,9 +571,7 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
* is set to TRUE, we strip the ID3v1.x and ID3v2 tags. Else, write ID3v2
* and/or ID3v1. */
if (g_settings_get_boolean (MainSettings, "id3-strip-empty")
- && !has_title && !has_artist && !has_album_artist && !has_album && !has_year &&
!has_track
- && !has_genre && !has_composer && !has_orig_artist && !has_copyright && !has_url
- && !has_encoded_by && !has_picture && !has_comment && !has_disc_number)//&& !has_song_len )
+ && strip_tags)
{
error_strip_id3v1 = ID3Tag_Strip(id3_tag,ID3TT_ID3V1);
error_strip_id3v2 = ID3Tag_Strip(id3_tag,ID3TT_ID3V2);
@@ -743,7 +729,8 @@ id3tag_write_file_v23tag (const ET_File *ETFile,
}
-gchar *Id3tag_Get_Error_Message(ID3_Err error)
+gchar *
+Id3tag_Get_Error_Message (ID3_Err error)
{
switch (error)
{
diff --git a/src/tags/id3_tag.h b/src/tags/id3_tag.h
index 342d22e..a63e423 100644
--- a/src/tags/id3_tag.h
+++ b/src/tags/id3_tag.h
@@ -38,10 +38,16 @@ guchar Id3tag_String_To_Genre (const gchar *genre);
gchar *et_id3tag_get_tpos_from_file_tag (const File_Tag *file_tag);
+
#ifdef ENABLE_MP3
#include <id3tag.h>
gboolean et_id3tag_fill_file_tag_from_id3tag (struct id3_tag *tag, File_Tag *file_tag);
void et_id3tag_set_id3_tag_from_file_tag (const File_Tag *FileTag, struct id3_tag *v1tag, struct id3_tag
*v2tag, gboolean *strip_tags);
+#ifdef ENABLE_ID3LIB
+#include <id3.h>
+gchar * Id3tag_Get_Error_Message (ID3_Err error);
+void et_id3tag_set_id3tag_from_file_tag (const File_Tag *FileTag, ID3Tag *id3_tag, gboolean *strip_tags);
+#endif /* ENABLE_ID3LIB */
#endif /* ENABLE_MP3 */
G_END_DECLS
diff --git a/src/tags/id3lib/c_wrapper.cpp b/src/tags/id3lib/c_wrapper.cpp
index 7f63406..2c92755 100644
--- a/src/tags/id3lib/c_wrapper.cpp
+++ b/src/tags/id3lib/c_wrapper.cpp
@@ -119,6 +119,30 @@ extern "C"
return headerInfo;
}
+ /* Filed as a patch against id3lib:
+ * http://sourceforge.net/p/id3lib/patches/75/ */
+ ID3_C_EXPORT size_t CCONV
+ ID3Tag_Render(const ID3Tag *tag, uchar *buffer, ID3_TagType tt)
+ {
+ size_t size = 0;
+ if (tag)
+ {
+ ID3_CATCH(size = reinterpret_cast<const ID3_Tag *>(tag)->Render(buffer, tt));
+ }
+ return size;
+ }
+
+ ID3_C_EXPORT size_t CCONV
+ ID3Tag_Size(const ID3Tag *tag)
+ {
+ size_t size = 0;
+ if (tag)
+ {
+ ID3_CATCH(size = reinterpret_cast<const ID3_Tag *>(tag)->Size());
+ }
+ return size;
+ }
+
// Call with :
// Mp3_Headerinfo* headerInfo = malloc(sizeof(Mp3_Headerinfo));
// ID3Tag_GetMp3HeaderInfo(tag, headerInfo);
diff --git a/src/tags/id3lib/id3_bugfix.h b/src/tags/id3lib/id3_bugfix.h
index 14e97a9..8a281d6 100644
--- a/src/tags/id3lib/id3_bugfix.h
+++ b/src/tags/id3lib/id3_bugfix.h
@@ -42,6 +42,8 @@ extern "C"
ID3_C_EXPORT ID3_TextEnc CCONV ID3Field_GetEncoding (const ID3Field *field);
ID3_C_EXPORT bool CCONV ID3Field_IsEncodable (const ID3Field *field);
ID3_C_EXPORT ID3_FieldType CCONV ID3Field_GetType (const ID3Field *field);
+ ID3_C_EXPORT size_t CCONV ID3Tag_Render (const ID3Tag *tag, uchar *buffer,
ID3_TagType tt);
+ ID3_C_EXPORT size_t CCONV ID3Tag_Size (const ID3Tag *tag);
//ID3_C_EXPORT ID3_FieldID CCONV ID3Field_GetID (const ID3Field *field);
ID3_C_EXPORT const Mp3_Headerinfo* CCONV ID3Tag_GetMp3HeaderInfo (ID3Tag *tag);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]