[easytag/wip/dsf-support: 5/9] Write ID3v2.4 tags to DSF files
- From: David King <davidk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [easytag/wip/dsf-support: 5/9] Write ID3v2.4 tags to DSF files
- Date: Fri, 21 Nov 2014 23:22:13 +0000 (UTC)
commit 57ab01d543ac7f1b0376fdd1b411589a8bfdc5d7
Author: David King <amigadave amigadave com>
Date: Sun Nov 9 23:53:05 2014 +0000
Write ID3v2.4 tags to DSF files
https://bugzilla.gnome.org/show_bug.cgi?id=708368
src/tag_area.c | 5 +
src/tags/dsf_tag.c | 361 ++++++++++++++++++++++++++++++++++++++++++++++++-
src/tags/id3_tag.h | 1 +
src/tags/id3v24_tag.c | 273 +++++++++++++++++++------------------
4 files changed, 504 insertions(+), 136 deletions(-)
---
diff --git a/src/tag_area.c b/src/tag_area.c
index c20c2ab..b35c619 100644
--- a/src/tag_area.c
+++ b/src/tag_area.c
@@ -3036,6 +3036,11 @@ et_tag_area_display_et_file (EtTagArea *self,
gtk_label_set_text (GTK_LABEL (priv->label), _("MP4/M4A/AAC Tag"));
break;
#endif
+#ifdef ENABLE_MP3
+ case DSF_TAG:
+ gtk_label_set_text (GTK_LABEL (priv->label), _("ID3 Tag"));
+ break;
+#endif
#ifdef ENABLE_WAVPACK
case WAVPACK_TAG:
gtk_label_set_text (GTK_LABEL (priv->label), _("Wavpack Tag"));
diff --git a/src/tags/dsf_tag.c b/src/tags/dsf_tag.c
index 5b82091..2300f4d 100644
--- a/src/tags/dsf_tag.c
+++ b/src/tags/dsf_tag.c
@@ -50,6 +50,20 @@ guint64_from_bytes (guchar *str)
return result;
}
+/* Write the 64-bit integer to the next 8 characters, in little-endian byte
+ * order. */
+static void
+guint64_to_bytes (guint64 field,
+ guchar *str)
+{
+ gsize i;
+
+ for (i = 0; i < 8; i++)
+ {
+ str[i] = (field >> i * 8) & 0xFF;
+ }
+}
+
gboolean
et_dsf_tag_read_file_tag (GFile *file,
File_Tag *FileTag,
@@ -183,6 +197,7 @@ 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"))
{
@@ -194,6 +209,7 @@ et_dsf_tag_read_file_tag (GFile *file,
| (ID3_TAG_VERSION_MAJOR (version) == 4));
}
#else
+#endif
update = (ID3_TAG_VERSION_MAJOR (version) < 4);
#endif
}
@@ -234,12 +250,349 @@ gboolean
et_dsf_tag_write_file_tag (const ET_File *ETFile,
GError **error)
{
- g_return_val_if_fail (ETFile != NULL, FALSE);
+ const File_Tag *FileTag;
+ const gchar *filename;
+ GFile *file;
+ GFileIOStream *iostream;
+ GInputStream *istream;
+ GOutputStream *ostream;
+ guchar header[DSF_HEADER_LENGTH];
+ gsize bytes_read;
+ guint64 file_size_header;
+ GFileInfo *info;
+ goffset file_size;
+ guint64 id3_offset;
+ GSeekable *seekable;
+ guchar id3_query[ID3_TAG_QUERYSIZE];
+ 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);
- /* TODO: Implement! */
- /* TODO: Read header, seek to ID3v2 offset, truncate file, write new tag,
- * using ID3v2.3 or 2.4 depending on id3v2-version-4 setting. */
+ FileTag = (File_Tag *)ETFile->FileTag->data;
+ filename = ((File_Name *)ETFile->FileNameCur->data)->value;
+
+ file = g_file_new_for_path (filename);
+ iostream = g_file_open_readwrite (file, NULL, error);
+ g_object_unref (file);
+
+ if (iostream == NULL)
+ {
+ return FALSE;
+ }
+
+ istream = g_io_stream_get_input_stream (G_IO_STREAM (iostream));
+
+ /* Read the complete header from the file. */
+ if (!g_input_stream_read_all (istream, &header, DSF_HEADER_LENGTH,
+ &bytes_read, NULL, error))
+ {
+ g_debug ("Only %" G_GSIZE_FORMAT " bytes out of %d "
+ "bytes were read", bytes_read, DSF_HEADER_LENGTH);
+ goto err;
+ }
+
+ if (memcmp (&header, DSF_HEADER_MAGIC, 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)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ _("Not a DSF file"));
+ goto err;
+ }
+
+ /* 12 (8 bytes) total file size. */
+ file_size_header = guint64_from_bytes (&header[DSF_HEADER_FILE_SIZE_OFFSET]);
+
+ info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (istream),
+ G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ NULL, error);
+
+ if (info == NULL)
+ {
+ goto err;
+ }
+
+ file_size = g_file_info_get_size (info);
+ g_object_unref (info);
+
+ if (file_size_header != file_size)
+ {
+ g_debug ("DSF file is %" G_GUINT64_FORMAT
+ " bytes, but the file size stored in the header is %"
+ G_GOFFSET_FORMAT " bytes", file_size, file_size_header);
+ }
+
+ /* 20 (8 bytes) metadata chunk offset, or 0 if no tag is present. */
+ id3_offset = guint64_from_bytes (&header[DSF_METADATA_CHUNK_OFFSET]);
+
+ if (id3_offset >= file_size)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ _("Invalid DSF header"));
+ goto err;
+ }
+
+ seekable = G_SEEKABLE (istream);
+
+ if (!g_seekable_can_seek (seekable))
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_BADF, "%s",
+ g_strerror (EBADF));
+ goto err;
+ }
+
+ if (id3_offset == 0)
+ {
+ /* No ID3v2 tag. */
+ id3_offset = file_size;
+
+ tag = id3_tag_new ();
+ tagsize = 0;
+ }
+ else
+ {
+ guchar *id3_buffer;
+
+ /* Read existing ID3v2 tag. */
+
+ /* Seek to the start of the metadata chunk. */
+ if (!g_seekable_seek (seekable, id3_offset, G_SEEK_SET, NULL, error))
+ {
+ goto err;
+ }
+
+ if (!g_input_stream_read_all (istream, id3_query, ID3_TAG_QUERYSIZE,
+ &bytes_read, NULL, error))
+ {
+ goto err;
+ }
+ else if (bytes_read != ID3_TAG_QUERYSIZE)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT, "%s",
+ _("Error reading tags from file"));
+ goto err;
+ }
+
+ if ((tagsize = id3_tag_query ((id3_byte_t const *)id3_query,
+ ID3_TAG_QUERYSIZE)) <= ID3_TAG_QUERYSIZE)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT, "%s",
+ _("Error reading tags from file"));
+ goto err;
+ }
+
+ id3_buffer = g_malloc (tagsize);
+ /* Copy the query buffer. */
+ memcpy (id3_buffer, id3_query, ID3_TAG_QUERYSIZE);
+
+ if (!g_input_stream_read_all (istream, &id3_buffer[ID3_TAG_QUERYSIZE],
+ tagsize - ID3_TAG_QUERYSIZE, &bytes_read,
+ NULL, error))
+ {
+ g_free (id3_buffer);
+ goto err;
+ }
+ else if (bytes_read != tagsize - ID3_TAG_QUERYSIZE)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT, "%s",
+ _("Error reading tags from file"));
+ 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. */
+ g_input_stream_close (istream, NULL, NULL);
+
+ 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))
+ {
+ 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)
+ {
+ 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;
+ }
+
+ 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;
+ }
+
+ 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);
+
+ eos_offset = g_seekable_tell (seekable);
+
+ /* If the new tag caused the file to change in size, update the size in the
+ * DSF header. */
+ if (eos_offset != file_size)
+ {
+ guchar new_file_size[8];
+ gsize bytes_written;
+
+ if (!g_seekable_seek (seekable, DSF_HEADER_FILE_SIZE_OFFSET,
+ G_SEEK_SET, NULL, error))
+ {
+ goto err;
+ }
+
+ guint64_to_bytes (eos_offset, &new_file_size[0]);
+
+ if (!g_output_stream_write_all (ostream, new_file_size, 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;
+ }
+ }
+
+ g_object_unref (iostream);
+ return TRUE;
+
+err:
+ g_object_unref (iostream);
return FALSE;
}
diff --git a/src/tags/id3_tag.h b/src/tags/id3_tag.h
index 5f74991..342d22e 100644
--- a/src/tags/id3_tag.h
+++ b/src/tags/id3_tag.h
@@ -41,6 +41,7 @@ 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);
#endif /* ENABLE_MP3 */
G_END_DECLS
diff --git a/src/tags/id3v24_tag.c b/src/tags/id3v24_tag.c
index b1347d2..da585ff 100644
--- a/src/tags/id3v24_tag.c
+++ b/src/tags/id3v24_tag.c
@@ -836,145 +836,37 @@ libid3tag_Get_Frame_Str (const struct id3_frame *frame,
return retval;
}
-
-/*
- * Write the ID3 tags to the file. Returns TRUE on success, else 0.
- */
-gboolean
-id3tag_write_file_v24tag (const ET_File *ETFile,
- GError **error)
+void
+et_id3tag_set_id3_tag_from_file_tag (const File_Tag *FileTag,
+ struct id3_tag *v1tag,
+ struct id3_tag *v2tag,
+ gboolean *strip_tags)
{
- const File_Tag *FileTag;
- const gchar *filename;
- struct id3_tag *v1tag, *v2tag;
struct id3_frame *frame;
- union id3_field *field;
- gchar *string1;
- Picture *pic;
- gboolean strip_tags = TRUE;
+ union id3_field *field;
+ gchar *string1;
guchar genre_value = ID3_INVALID_GENRE;
- gboolean success;
-
- g_return_val_if_fail (ETFile != NULL && ETFile->FileTag != NULL, FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
- FileTag = (File_Tag *)ETFile->FileTag->data;
- filename = ((File_Name *)ETFile->FileNameCur->data)->value;
-
- v1tag = v2tag = NULL;
-
- /* Write ID3v2 tag. */
- if (g_settings_get_boolean (MainSettings, "id3v2-enabled"))
- {
- struct id3_file *file;
- struct id3_tag *tmptag;
- unsigned tagsize;
- id3_byte_t *tmpbuf = NULL;
-
- /* Read old v2 tag */
- if ((file = id3_file_open(filename, ID3_FILE_MODE_READWRITE)) == NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
- _("Error reading tags from file"));
- return FALSE;
- }
-
- if ((tmptag = id3_file_tag(file)) == NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
- _("Error reading tags from file"));
- id3_file_close(file);
- return FALSE;
- }
-
- id3_tag_options(tmptag, ID3_TAG_OPTION_UNSYNCHRONISATION
- | ID3_TAG_OPTION_ID3V1
- | ID3_TAG_OPTION_COMPRESSION
- | ID3_TAG_OPTION_APPENDEDTAG,
- //ID3_TAG_OPTION_UNSYNCHRONISATION); // Taglib doesn't support frames with
unsynchronisation (patch from Alexey Illarionov) http://bugs.kde.org/show_bug.cgi?id=138829
- 0);
-
- /* XXX Create new tag and copy all frames*/
- tagsize = id3_tag_render(tmptag, NULL);
- if ((tagsize > 10)
- && (tmpbuf = g_try_malloc(tagsize))
- && (id3_tag_render(tmptag, tmpbuf) != 0)
- )
- v2tag = id3_tag_parse(tmpbuf, tagsize);
- g_free(tmpbuf);
-
- if (v2tag == NULL)
- {
- if ((v2tag = id3_tag_new()) == NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
- _("Error reading tags from file"));
- id3_file_close(file);
- return FALSE;
- }
- }
-
- id3_file_close(file);
-
- /* Set padding XXX */
- if ((v2tag->paddedsize < 1024)
- || ((v2tag->paddedsize > 4096) && (tagsize < 1024))
- )
- v2tag->paddedsize = 1024;
-
- /* Set options */
- id3_tag_options(v2tag, ID3_TAG_OPTION_UNSYNCHRONISATION
- | ID3_TAG_OPTION_APPENDEDTAG
- | ID3_TAG_OPTION_ID3V1
- | ID3_TAG_OPTION_CRC
- | ID3_TAG_OPTION_COMPRESSION,
- //ID3_TAG_OPTION_UNSYNCHRONISATION); // Taglib doesn't support frames with
unsynchronisation (patch from Alexey Illarionov) http://bugs.kde.org/show_bug.cgi?id=138829
- 0);
-
- if (g_settings_get_boolean (MainSettings, "id3v2-crc32"))
- {
- id3_tag_options (v2tag, ID3_TAG_OPTION_CRC, ~0);
- }
- if (g_settings_get_boolean (MainSettings, "id3v2-compression"))
- {
- id3_tag_options (v2tag, ID3_TAG_OPTION_COMPRESSION, ~0);
- }
- }
-
- /* Write ID3v1 tag. */
- if (g_settings_get_boolean (MainSettings, "id3v1-enabled"))
- {
- v1tag = id3_tag_new();
- if (!v1tag)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
- _("Error reading tags from file"));
- return FALSE;
- }
-
- id3_tag_options(v1tag, ID3_TAG_OPTION_ID3V1, ~0);
- }
-
+ Picture *pic;
/*********
* Title *
*********/
- etag_set_tags(FileTag->title, ID3_FRAME_TITLE, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, &strip_tags);
+ etag_set_tags(FileTag->title, ID3_FRAME_TITLE, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, strip_tags);
/**********
* Artist *
**********/
- etag_set_tags(FileTag->artist, ID3_FRAME_ARTIST, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, &strip_tags);
+ etag_set_tags(FileTag->artist, ID3_FRAME_ARTIST, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, strip_tags);
/**********
* Album Artist *
**********/
- etag_set_tags(FileTag->album_artist, "TPE2", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, &strip_tags);
+ etag_set_tags(FileTag->album_artist, "TPE2", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, strip_tags);
/*********
* Album *
*********/
- etag_set_tags(FileTag->album, ID3_FRAME_ALBUM, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, &strip_tags);
+ etag_set_tags(FileTag->album, ID3_FRAME_ALBUM, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, strip_tags);
/***************
* Part of set *
@@ -983,14 +875,14 @@ id3tag_write_file_v24tag (const ET_File *ETFile,
{
string1 = et_id3tag_get_tpos_from_file_tag (FileTag);
etag_set_tags (string1, "TPOS", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag,
- &strip_tags);
+ strip_tags);
g_free (string1);
}
/********
* Year *
********/
- etag_set_tags(FileTag->year, ID3_FRAME_YEAR, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, &strip_tags);
+ etag_set_tags(FileTag->year, ID3_FRAME_YEAR, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, strip_tags);
/*************************
* Track and Total Track *
@@ -1002,8 +894,8 @@ id3tag_write_file_v24tag (const ET_File *ETFile,
else
string1 = NULL;
- etag_set_tags(string1 ? string1 : FileTag->track, ID3_FRAME_TRACK, ID3_FIELD_TYPE_STRINGLIST, NULL,
v2tag, &strip_tags);
- etag_set_tags(FileTag->track, ID3_FRAME_TRACK, ID3_FIELD_TYPE_STRINGLIST, v1tag, NULL, &strip_tags);
+ etag_set_tags(string1 ? string1 : FileTag->track, ID3_FRAME_TRACK, ID3_FIELD_TYPE_STRINGLIST, NULL,
v2tag, strip_tags);
+ etag_set_tags(FileTag->track, ID3_FRAME_TRACK, ID3_FIELD_TYPE_STRINGLIST, v1tag, NULL, strip_tags);
g_free(string1);
/*********
@@ -1026,33 +918,33 @@ id3tag_write_file_v24tag (const ET_File *ETFile,
string1 = g_strdup_printf ("(%d)",genre_value);
}
- etag_set_tags(string1, ID3_FRAME_GENRE, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, &strip_tags);
+ etag_set_tags(string1, ID3_FRAME_GENRE, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, strip_tags);
g_free(string1);
/***********
* Comment *
***********/
- etag_set_tags(FileTag->comment, ID3_FRAME_COMMENT, ID3_FIELD_TYPE_STRINGFULL, v1tag, v2tag, &strip_tags);
+ etag_set_tags(FileTag->comment, ID3_FRAME_COMMENT, ID3_FIELD_TYPE_STRINGFULL, v1tag, v2tag, strip_tags);
/************
* Composer *
************/
- etag_set_tags(FileTag->composer, "TCOM", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, &strip_tags);
+ etag_set_tags(FileTag->composer, "TCOM", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, strip_tags);
/*******************
* Original artist *
*******************/
- etag_set_tags(FileTag->orig_artist, "TOPE", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, &strip_tags);
+ etag_set_tags(FileTag->orig_artist, "TOPE", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, strip_tags);
/*************
* Copyright *
*************/
- etag_set_tags(FileTag->copyright, "TCOP", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, &strip_tags);
+ etag_set_tags(FileTag->copyright, "TCOP", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, strip_tags);
/*******
* URL *
*******/
- etag_set_tags(FileTag->url, "WXXX", ID3_FIELD_TYPE_LATIN1, NULL, v2tag, &strip_tags);
+ etag_set_tags(FileTag->url, "WXXX", ID3_FIELD_TYPE_LATIN1, NULL, v2tag, strip_tags);
/***************
* Encoded by *
@@ -1065,7 +957,7 @@ id3tag_write_file_v24tag (const ET_File *ETFile,
// strip_tags = FALSE;
//}else
// Save encoder name in TENC frame instead of the TXX frame
- etag_set_tags(FileTag->encoded_by, "TENC", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, &strip_tags);
+ etag_set_tags(FileTag->encoded_by, "TENC", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, strip_tags);
if (v2tag)
Id3tag_delete_txxframes(v2tag, EASYTAG_STRING_ENCODEDBY, 0);
@@ -1116,6 +1008,123 @@ id3tag_write_file_v24tag (const ET_File *ETFile,
* File length (in milliseconds) DISCARD*
****************************************/
+}
+
+/*
+ * Write the ID3 tags to the file. Returns TRUE on success, else 0.
+ */
+gboolean
+id3tag_write_file_v24tag (const ET_File *ETFile,
+ GError **error)
+{
+ const File_Tag *FileTag;
+ const gchar *filename;
+ struct id3_tag *v1tag, *v2tag;
+ gboolean strip_tags = TRUE;
+ gboolean success;
+
+ g_return_val_if_fail (ETFile != NULL && ETFile->FileTag != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ FileTag = (File_Tag *)ETFile->FileTag->data;
+ filename = ((File_Name *)ETFile->FileNameCur->data)->value;
+
+ v1tag = v2tag = NULL;
+
+ /* Write ID3v2 tag. */
+ if (g_settings_get_boolean (MainSettings, "id3v2-enabled"))
+ {
+ struct id3_file *file;
+ struct id3_tag *tmptag;
+ unsigned tagsize;
+ id3_byte_t *tmpbuf = NULL;
+
+ /* Read old v2 tag */
+ if ((file = id3_file_open(filename, ID3_FILE_MODE_READWRITE)) == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ _("Error reading tags from file"));
+ return FALSE;
+ }
+
+ if ((tmptag = id3_file_tag(file)) == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ _("Error reading tags from file"));
+ id3_file_close(file);
+ return FALSE;
+ }
+
+ id3_tag_options(tmptag, ID3_TAG_OPTION_UNSYNCHRONISATION
+ | ID3_TAG_OPTION_ID3V1
+ | ID3_TAG_OPTION_COMPRESSION
+ | ID3_TAG_OPTION_APPENDEDTAG,
+ //ID3_TAG_OPTION_UNSYNCHRONISATION); // Taglib doesn't support frames with
unsynchronisation (patch from Alexey Illarionov) http://bugs.kde.org/show_bug.cgi?id=138829
+ 0);
+
+ /* XXX Create new tag and copy all frames*/
+ tagsize = id3_tag_render(tmptag, NULL);
+ if ((tagsize > 10)
+ && (tmpbuf = g_try_malloc(tagsize))
+ && (id3_tag_render(tmptag, tmpbuf) != 0)
+ )
+ v2tag = id3_tag_parse(tmpbuf, tagsize);
+ g_free(tmpbuf);
+
+ if (v2tag == NULL)
+ {
+ if ((v2tag = id3_tag_new()) == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ _("Error reading tags from file"));
+ id3_file_close(file);
+ return FALSE;
+ }
+ }
+
+ id3_file_close(file);
+
+ /* Set padding XXX */
+ if ((v2tag->paddedsize < 1024)
+ || ((v2tag->paddedsize > 4096) && (tagsize < 1024))
+ )
+ v2tag->paddedsize = 1024;
+
+ /* Set options */
+ id3_tag_options(v2tag, ID3_TAG_OPTION_UNSYNCHRONISATION
+ | ID3_TAG_OPTION_APPENDEDTAG
+ | ID3_TAG_OPTION_ID3V1
+ | ID3_TAG_OPTION_CRC
+ | ID3_TAG_OPTION_COMPRESSION,
+ //ID3_TAG_OPTION_UNSYNCHRONISATION); // Taglib doesn't support frames with
unsynchronisation (patch from Alexey Illarionov) http://bugs.kde.org/show_bug.cgi?id=138829
+ 0);
+
+ if (g_settings_get_boolean (MainSettings, "id3v2-crc32"))
+ {
+ id3_tag_options (v2tag, ID3_TAG_OPTION_CRC, ~0);
+ }
+ if (g_settings_get_boolean (MainSettings, "id3v2-compression"))
+ {
+ id3_tag_options (v2tag, ID3_TAG_OPTION_COMPRESSION, ~0);
+ }
+ }
+
+ /* Write ID3v1 tag. */
+ if (g_settings_get_boolean (MainSettings, "id3v1-enabled"))
+ {
+ v1tag = id3_tag_new();
+ if (!v1tag)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ _("Error reading tags from file"));
+ return FALSE;
+ }
+
+ id3_tag_options(v1tag, ID3_TAG_OPTION_ID3V1, ~0);
+ }
+
+ et_id3tag_set_id3_tag_from_file_tag (FileTag, v1tag, v2tag, &strip_tags);
+
/*********************************
* Update id3v1.x and id3v2 tags *
*********************************/
@@ -1406,7 +1415,7 @@ id3taglib_set_field(struct id3_frame *frame,
}
-static int
+int
etag_set_tags (const gchar *str,
const char *frame_name,
enum id3_field_type field_type,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]