From ba15707b292d827bdce732e7713b26fae3f75c74 Mon Sep 17 00:00:00 2001 From: Alex Bennee Date: Wed, 14 Jul 2010 15:57:06 +0100 Subject: EasyTag 2.1.1 --- src/flac_tag.c | 1029 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1029 insertions(+) create mode 100755 src/flac_tag.c (limited to 'src/flac_tag.c') diff --git a/src/flac_tag.c b/src/flac_tag.c new file mode 100755 index 0000000..a76e1cc --- /dev/null +++ b/src/flac_tag.c @@ -0,0 +1,1029 @@ +/* flac_tag.c - 2003/12/27 */ +/* + * EasyTAG - Tag editor for MP3 and Ogg Vorbis files + * Copyright (C) 2001-2003 Jerome Couderc + * Copyright (C) 2003 Pavel Minayev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#ifdef ENABLE_FLAC + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "easytag.h" +#include "flac_tag.h" +#include "vcedit.h" +#include "et_core.h" +#include "id3_tag.h" +#include "log.h" +#include "misc.h" +#include "setting.h" +#include "picture.h" +#include "charset.h" + + +/*************** + * Declaration * + ***************/ + +#define MULTIFIELD_SEPARATOR " - " + +/* Patch from Josh Coalson + * FLAC 1.1.3 has FLAC_API_VERSION_CURRENT == 8 * + * by LEGACY_FLAC we mean pre-FLAC 1.1.3; in FLAC 1.1.3 the FLAC__FileDecoder was merged into the FLAC__StreamDecoder */ +#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT < 8 +#define LEGACY_FLAC // For FLAC version < 1.1.3 +#else +#undef LEGACY_FLAC +#endif + + +/* FLAC uses Ogg Vorbis comments + * Ogg Vorbis fields names : + * - TITLE : Track name + * - VERSION : The version field may be used to differentiate multiple version of the same track title in a single collection. (e.g. remix info) + * - ALBUM : The collection name to which this track belongs + * - TRACKNUMBER : The track number of this piece if part of a specific larger collection or album + * - TRACKTOTAL : + * - ARTIST : Track performer + * - ORGANIZATION : Name of the organization producing the track (i.e. the 'record label') + * - DESCRIPTION : A short text description of the contents + * - COMME?T : same than DESCRIPTION + * - GENRE : A short text indication of music genre + * - DATE : Date the track was recorded + * - LOCATION : Location where track was recorded + * - COPYRIGHT : Copyright information + * - ISRC : ISRC number for the track; see the ISRC intro page for more information on ISRC numbers. + * + * Field names should not be 'internationalized'; this is a concession to simplicity + * not an attempt to exclude the majority of the world that doesn't speak English. + * Field *contents*, however, are represented in UTF-8 to allow easy representation + * of any language. + */ + + + +/************** + * Prototypes * + **************/ +gboolean Flac_Tag_Write_File (FILE *file_in, gchar *filename_in, vcedit_state *state); + + +/************* + * Functions * + *************/ + +/* + * Read tag data from a FLAC file. + * Note: + * - if field is found but contains no info (strlen(str)==0), we don't read it + */ +gboolean Flac_Tag_Read_File_Tag (gchar *filename, File_Tag *FileTag) +{ + FLAC__Metadata_SimpleIterator *iter; + FLAC__StreamMetadata *vc_block; + FLAC__StreamMetadata_VorbisComment *vc; + FLAC__StreamMetadata_VorbisComment_Entry *field; + gchar *field_value; + gchar *field_value_tmp; + gchar *string = NULL; + gint field_num; + gint field_len; + guint i; + + + if (!filename || !FileTag) + return FALSE; + + flac_error_msg = NULL; + + iter = FLAC__metadata_simple_iterator_new(); + if ( iter == NULL || !FLAC__metadata_simple_iterator_init(iter, filename, true, false) ) + { + gchar *filename_utf8 = filename_to_display(filename); + if ( iter == NULL ) + { +#ifdef WIN32 + const char ** const iter = FLAC__Metadata_SimpleIteratorStatusString; /* this is for win32 auto-import of this external symbol works */ + flac_error_msg = iter[FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR]; +#else + flac_error_msg = FLAC__Metadata_SimpleIteratorStatusString[FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR]; +#endif + }else + { + flac_error_msg = FLAC__Metadata_SimpleIteratorStatusString[FLAC__metadata_simple_iterator_status(iter)]; + FLAC__metadata_simple_iterator_delete(iter); + } + + Log_Print(_("ERROR while opening file: '%s' as FLAC (%s)."),filename_utf8,flac_error_msg); + g_free(filename_utf8); + return FALSE; + } + + /* libFLAC is able to detect (and skip) ID3v2 tags by itself */ + + /* Find the VORBIS_COMMENT block */ + while ( FLAC__metadata_simple_iterator_get_block_type(iter) != FLAC__METADATA_TYPE_VORBIS_COMMENT ) + { + if ( !FLAC__metadata_simple_iterator_next(iter) ) + { + /* End of metadata: comment block not found, nothing to read */ + FLAC__metadata_simple_iterator_delete(iter); + return TRUE; + } + } + + /* Get comments from block */ + vc_block = FLAC__metadata_simple_iterator_get_block(iter); + vc = &vc_block->data.vorbis_comment; + + /* Get vendor string */ + /*{ + FLAC__StreamMetadata_VorbisComment_Entry vce; + vce = vc->vendor_string; + g_print("File %s : \n",filename); + g_print(" - FLAC File vendor string : '%s'\n",g_strndup(vce.entry,vce.length)); + g_print(" - FLAC Lib vendor string : '%s'\n",FLAC__VENDOR_STRING); + }*/ + + + /********* + * Title * + *********/ + field_num = 0; + while ( (field_num = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,field_num,"TITLE")) >= 0 ) + { + /* Extract field value */ + field = &vc->comments[field_num++]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + if (FileTag->title==NULL) + FileTag->title = g_strdup(field_value); + else + FileTag->title = g_strconcat(FileTag->title,MULTIFIELD_SEPARATOR,field_value,NULL); + g_free(field_value); + } + } + } + + /********** + * Artist * + **********/ + field_num = 0; + while ( (field_num = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,field_num,"ARTIST")) >= 0 ) + { + /* Extract field value */ + field = &vc->comments[field_num++]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + if (FileTag->artist==NULL) + FileTag->artist = g_strdup(field_value); + else + FileTag->artist = g_strconcat(FileTag->artist,MULTIFIELD_SEPARATOR,field_value,NULL); + g_free(field_value); + } + } + } + + /********* + * Album * + *********/ + field_num = 0; + while ( (field_num = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,field_num,"ALBUM")) >= 0 ) + { + /* Extract field value */ + field = &vc->comments[field_num++]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + if (FileTag->album==NULL) + FileTag->album = g_strdup(field_value); + else + FileTag->album = g_strconcat(FileTag->album,MULTIFIELD_SEPARATOR,field_value,NULL); + g_free(field_value); + } + } + } + + /*************** + * Disc Number * + ***************/ + if ( (field_num = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,0,"DISCNUMBER")) >= 0 ) + { + /* Extract field value */ + field = &vc->comments[field_num]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + FileTag->disc_number = field_value; + } + } + } + + /******** + * Year * + ********/ + if ( (field_num = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,0,"DATE")) >= 0 ) + { + /* Extract field value */ + field = &vc->comments[field_num]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + FileTag->year = field_value; + } + } + } + + /************************* + * Track and Total Track * + *************************/ + if ( (field_num = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,0,"TRACKTOTAL")) >= 0 ) + { + /* Extract field value */ + field = &vc->comments[field_num]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + if (NUMBER_TRACK_FORMATED) + { + FileTag->track_total = g_strdup_printf("%.*d",NUMBER_TRACK_FORMATED_SPIN_BUTTON,atoi(field_value)); + }else + { + FileTag->track_total = g_strdup(field_value); + } + g_free(field_value); + } + } + // Below is also filled track_total if not done here + } + + if ( (field_num = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,0,"TRACKNUMBER")) >= 0 ) + { + /* Extract field value */ + field = &vc->comments[field_num]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + string = g_utf8_strchr(field_value, -1, '/'); + if (NUMBER_TRACK_FORMATED) + { + // If track_total not filled before, try now... + if (string && !FileTag->track_total) + { + FileTag->track_total = g_strdup_printf("%.*d",NUMBER_TRACK_FORMATED_SPIN_BUTTON,atoi(string+1)); + *string = '\0'; + } + FileTag->track = g_strdup_printf("%.*d",NUMBER_TRACK_FORMATED_SPIN_BUTTON,atoi(field_value)); + }else + { + if (string && !FileTag->track_total) + { + FileTag->track_total = g_strdup(string+1); + *string = '\0'; + } + FileTag->track = g_strdup(field_value); + } + g_free(field_value); + } + } + } + + /********* + * Genre * + *********/ + field_num = 0; + while ( (field_num = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,field_num,"GENRE")) >= 0 ) + { + /* Extract field value */ + field = &vc->comments[field_num++]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + if (FileTag->genre==NULL) + FileTag->genre = g_strdup(field_value); + else + FileTag->genre = g_strconcat(FileTag->genre,MULTIFIELD_SEPARATOR,field_value,NULL); + g_free(field_value); + } + } + } + + /*********** + * Comment * + ***********/ + field_num = 0; + while ( 1 ) + { + gint field_num1, field_num2; + + // The comment field can take two forms... + field_num1 = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,field_num,"DESCRIPTION"); + field_num2 = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,field_num,"COMMENT"); + + if (field_num1 >= 0 && field_num2 >= 0) + // Note : We set field_num to the last "comment" field to avoid to concatenate + // the DESCRIPTION and COMMENT field if there are both present (EasyTAG writes the both...) + if (field_num1 < field_num2) + field_num = field_num2; + else + field_num = field_num1; + else if (field_num1 >= 0) + field_num = field_num1; + else if (field_num2 >= 0) + field_num = field_num2; + else + break; + + /* Extract field value */ + field = &vc->comments[field_num++]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + if (FileTag->comment==NULL) + FileTag->comment = g_strdup(field_value); + else + FileTag->comment = g_strconcat(FileTag->comment,MULTIFIELD_SEPARATOR,field_value,NULL); + g_free(field_value); + } + } + } + + /************ + * Composer * + ************/ + field_num = 0; + while ( (field_num = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,field_num,"COMPOSER")) >= 0 ) + { + /* Extract field value */ + field = &vc->comments[field_num++]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + if (FileTag->composer==NULL) + FileTag->composer = g_strdup(field_value); + else + FileTag->composer = g_strconcat(FileTag->composer,MULTIFIELD_SEPARATOR,field_value,NULL); + g_free(field_value); + } + } + } + + /******************* + * Original artist * + *******************/ + field_num = 0; + while ( (field_num = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,field_num,"PERFORMER")) >= 0 ) + { + /* Extract field value */ + field = &vc->comments[field_num++]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + if (FileTag->orig_artist==NULL) + FileTag->orig_artist = g_strdup(field_value); + else + FileTag->orig_artist = g_strconcat(FileTag->orig_artist,MULTIFIELD_SEPARATOR,field_value,NULL); + g_free(field_value); + } + } + } + + /************* + * Copyright * + *************/ + field_num = 0; + while ( (field_num = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,field_num,"COPYRIGHT")) >= 0 ) + { + /* Extract field value */ + field = &vc->comments[field_num++]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + if (FileTag->copyright==NULL) + FileTag->copyright = g_strdup(field_value); + else + FileTag->copyright = g_strconcat(FileTag->copyright,MULTIFIELD_SEPARATOR,field_value,NULL); + g_free(field_value); + } + } + } + + /******* + * URL * + *******/ + field_num = 0; + while ( (field_num = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,field_num,"LICENSE")) >= 0 ) + { + /* Extract field value */ + field = &vc->comments[field_num++]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + if (FileTag->url==NULL) + FileTag->url = g_strdup(field_value); + else + FileTag->url = g_strconcat(FileTag->url,MULTIFIELD_SEPARATOR,field_value,NULL); + g_free(field_value); + } + } + } + + /************** + * Encoded by * + **************/ + field_num = 0; + while ( (field_num = FLAC__metadata_object_vorbiscomment_find_entry_from(vc_block,field_num,"ENCODED-BY")) >= 0 ) + { + /* Extract field value */ + field = &vc->comments[field_num++]; + field_value = memchr(field->entry, '=', field->length); + + if (field_value) + { + field_value++; + if ( field_value && g_utf8_strlen(field_value, -1) > 0 ) + { + field_len = field->length - (field_value - (gchar*) field->entry); + field_value_tmp = g_strndup(field_value, field_len); + field_value = Try_To_Validate_Utf8_String(field_value_tmp); + g_free(field_value_tmp); + if (FileTag->encoded_by==NULL) + FileTag->encoded_by = g_strdup(field_value); + else + FileTag->encoded_by = g_strconcat(FileTag->encoded_by,MULTIFIELD_SEPARATOR,field_value,NULL); + g_free(field_value); + } + } + } + + + /*********** + * Picture * + ***********/ + // For FLAC > 1.1.3 + #ifndef LEGACY_FLAC + + #endif + + + /*************************** + * Save unsupported fields * + ***************************/ + for (i=0;i<(guint)vc->num_comments;i++) + { + field = &vc->comments[i]; + if ( strncasecmp((gchar *)field->entry,"TITLE=", MIN(6, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"ARTIST=", MIN(7, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"ALBUM=", MIN(6, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"DISCNUMBER=", MIN(11, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"DATE=", MIN(5, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"TRACKNUMBER=", MIN(12, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"TRACKTOTAL=", MIN(11, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"GENRE=", MIN(6, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"DESCRIPTION=", MIN(12, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"COMMENT=", MIN(8, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"COMPOSER=", MIN(9, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"PERFORMER=", MIN(10, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"COPYRIGHT=", MIN(10, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"LICENSE=", MIN(8, field->length)) != 0 + && strncasecmp((gchar *)field->entry,"ENCODED-BY=", MIN(11, field->length)) != 0 ) + { + //g_print("custom %*s\n", field->length, field->entry); + FileTag->other = g_list_append(FileTag->other,g_strndup((const gchar *)field->entry, field->length)); + } + } + + FLAC__metadata_object_delete(vc_block); + FLAC__metadata_simple_iterator_delete(iter); + +#ifdef ENABLE_MP3 + /* If no FLAC vorbis tag found : we try to get the ID3 tag if it exists + * (will be deleted when writing the tag */ + if ( FileTag->title == NULL + && FileTag->artist == NULL + && FileTag->album == NULL + && FileTag->disc_number == NULL + && FileTag->year == NULL + && FileTag->track == NULL + && FileTag->track_total == NULL + && FileTag->genre == NULL + && FileTag->comment == NULL + && FileTag->composer == NULL + && FileTag->orig_artist == NULL + && FileTag->copyright == NULL + && FileTag->url == NULL + && FileTag->encoded_by == NULL) + { + gint rc = Id3tag_Read_File_Tag(filename,FileTag); + + // If an ID3 tag has been found (and no FLAC tag), we mark the file as + // unsaved to rewrite a flac tag + if ( FileTag->title != NULL + || FileTag->artist != NULL + || FileTag->album != NULL + || FileTag->disc_number != NULL + || FileTag->year != NULL + || FileTag->track != NULL + || FileTag->track_total != NULL + || FileTag->genre != NULL + || FileTag->comment != NULL + || FileTag->composer != NULL + || FileTag->orig_artist != NULL + || FileTag->copyright != NULL + || FileTag->url != NULL + || FileTag->encoded_by != NULL) + { + FileTag->saved = FALSE; + } + + return rc; + } + + /* Part to get cover artist : + * If we have read the ID3 tag previously we don't arrive here (and we have + * the picture if it exists) + * Else the ID3 tag wasn't read (as there was data in FLAC tag) so we try + * to read it only to get the picture (not supported by the FLAC tag) */ + if (WRITE_ID3_TAGS_IN_FLAC_FILE && FileTag->picture == NULL) + { + File_Tag *FileTag_tmp = ET_File_Tag_Item_New(); + gint rc = Id3tag_Read_File_Tag(filename,FileTag_tmp); + if (rc && FileTag_tmp->picture) + { + // Copy picture to FileTag + FileTag->picture = Picture_Copy(FileTag_tmp->picture); + } + + ET_Free_File_Tag_Item(FileTag_tmp); + + return rc; + } +#endif + + return TRUE; +} + + +gboolean Flac_Tag_Write_File_Tag (ET_File *ETFile) +{ + File_Tag *FileTag; + gchar *filename_utf8, *filename; + gchar *basename_utf8; + FLAC__Metadata_SimpleIterator *iter; + FLAC__StreamMetadata *vc_block; + FLAC__StreamMetadata_VorbisComment_Entry field; + FLAC__bool write_ok; + gchar *string; + GList *list; + // To get original vendor string + FLAC__StreamMetadata *vc_block_svg = NULL; + FLAC__StreamMetadata_VorbisComment *vc_svg; + FLAC__StreamMetadata_VorbisComment_Entry field_svg; + gboolean vc_found_svg = TRUE; + + + if (!ETFile || !ETFile->FileTag) + return FALSE; + + FileTag = (File_Tag *)ETFile->FileTag->data; + filename = ((File_Name *)ETFile->FileNameCur->data)->value; + filename_utf8 = ((File_Name *)ETFile->FileNameCur->data)->value_utf8; + flac_error_msg = NULL; + + /* libFLAC is able to detect (and skip) ID3v2 tags by itself */ + + iter = FLAC__metadata_simple_iterator_new(); + if ( iter == NULL || !FLAC__metadata_simple_iterator_init(iter,filename,false,false) ) + { + if ( iter == NULL ) + { +#ifdef WIN32 + const char **iter = FLAC__Metadata_SimpleIteratorStatusString; /* this is for win32 auto-import of this external symbol works */ + flac_error_msg = iter[FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR]; +#else + flac_error_msg = FLAC__Metadata_SimpleIteratorStatusString[FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR]; +#endif + }else + { + flac_error_msg = FLAC__Metadata_SimpleIteratorStatusString[FLAC__metadata_simple_iterator_status(iter)]; + FLAC__metadata_simple_iterator_delete(iter); + } + + Log_Print(_("ERROR while opening file: '%s' as FLAC (%s)."),filename_utf8,flac_error_msg); + return FALSE; + } + + /* Find the VORBIS_COMMENT block to get original vendor string */ + while ( FLAC__metadata_simple_iterator_get_block_type(iter) != FLAC__METADATA_TYPE_VORBIS_COMMENT ) + { + if ( !FLAC__metadata_simple_iterator_next(iter) ) + { + /* End of metadata: comment block not found, nothing to read */ + vc_found_svg = FALSE; + break; + } + } + if (vc_found_svg) + { + /* Get comments from block */ + vc_block_svg = FLAC__metadata_simple_iterator_get_block(iter); + vc_svg = &vc_block_svg->data.vorbis_comment; + /* Get original vendor string */ + field_svg = vc_svg->vendor_string; + } + + + vc_block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); + + /* Set the original vendor string else it is version of library */ + if (vc_found_svg) + FLAC__metadata_object_vorbiscomment_set_vendor_string(vc_block, field_svg, true); + + + /********* + * Title * + *********/ + if ( FileTag->title ) + { + string = g_strconcat("TITLE=",FileTag->title,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); // Warning : g_utf8_strlen doesn't count the multibyte characters. Here we need the allocated size. + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + + /********** + * Artist * + **********/ + if ( FileTag->artist ) + { + string = g_strconcat("ARTIST=",FileTag->artist,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + + /********* + * Album * + *********/ + if ( FileTag->album ) + { + string = g_strconcat("ALBUM=",FileTag->album,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + + /*************** + * Disc Number * + ***************/ + if ( FileTag->disc_number ) + { + string = g_strconcat("DISCNUMBER=",FileTag->disc_number,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + + /******** + * Year * + ********/ + if ( FileTag->year ) + { + string = g_strconcat("DATE=",FileTag->year,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + + /************************* + * Track and Total Track * + *************************/ + if ( FileTag->track ) + { + string = g_strconcat("TRACKNUMBER=",FileTag->track,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + if ( FileTag->track_total /*&& strlen(FileTag->track_total)>0*/ ) + { + string = g_strconcat("TRACKTOTAL=",FileTag->track_total,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + + /********* + * Genre * + *********/ + if ( FileTag->genre ) + { + string = g_strconcat("GENRE=",FileTag->genre,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + + /*********** + * Comment * + ***********/ + // We write the comment using the "both" format + if ( FileTag->comment ) + { + string = g_strconcat("DESCRIPTION=",FileTag->comment,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + + string = g_strconcat("COMMENT=",FileTag->comment,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + + /************ + * Composer * + ************/ + if ( FileTag->composer ) + { + string = g_strconcat("COMPOSER=",FileTag->composer,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + + /******************* + * Original artist * + *******************/ + if ( FileTag->orig_artist ) + { + string = g_strconcat("PERFORMER=",FileTag->orig_artist,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + + /************* + * Copyright * + *************/ + if ( FileTag->copyright ) + { + string = g_strconcat("COPYRIGHT=",FileTag->copyright,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + + /******* + * URL * + *******/ + if ( FileTag->url ) + { + string = g_strconcat("LICENSE=",FileTag->url,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + + /************** + * Encoded by * + **************/ + if ( FileTag->encoded_by ) + { + string = g_strconcat("ENCODED-BY=",FileTag->encoded_by,NULL); + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + g_free(string); + } + + + /************************** + * Set unsupported fields * + **************************/ + list = FileTag->other; + while (list) + { + if (list->data) + { + string = (gchar*)list->data; + field.entry = (FLAC__byte *)string; + field.length = strlen(string); + FLAC__metadata_object_vorbiscomment_insert_comment(vc_block,vc_block->data.vorbis_comment.num_comments,field,true); + } + list = list->next; + } + + /* Find the VORBIS_COMMENT block */ + while ( FLAC__metadata_simple_iterator_get_block_type(iter) != FLAC__METADATA_TYPE_VORBIS_COMMENT ) + { + if ( !FLAC__metadata_simple_iterator_next(iter) ) + break; + } + + + /* + * Write FLAC tag (as Vorbis comment) + */ + if ( FLAC__metadata_simple_iterator_get_block_type(iter) != FLAC__METADATA_TYPE_VORBIS_COMMENT ) + { + /* End of metadata: no comment block, so insert one */ + write_ok = FLAC__metadata_simple_iterator_insert_block_after(iter,vc_block,true); + }else + { + write_ok = FLAC__metadata_simple_iterator_set_block(iter,vc_block,true); + } + + if ( !write_ok ) + { + flac_error_msg = FLAC__Metadata_SimpleIteratorStatusString[FLAC__metadata_simple_iterator_status(iter)]; + Log_Print(_("ERROR: Failed to write comments to file '%s' (%s)."),filename_utf8,flac_error_msg); + FLAC__metadata_simple_iterator_delete(iter); + FLAC__metadata_object_delete(vc_block); + return FALSE; + }else + { + basename_utf8 = g_path_get_basename(filename_utf8); + Log_Print(_("Written tag of '%s'"),basename_utf8); + g_free(basename_utf8); + } + + FLAC__metadata_simple_iterator_delete(iter); + FLAC__metadata_object_delete(vc_block); + if (vc_found_svg) + FLAC__metadata_object_delete(vc_block_svg); + +#ifdef ENABLE_MP3 + /* + * Write also the ID3 tags (ID3v1 and/or ID3v2) if wanted (as needed by some players) + */ + if (WRITE_ID3_TAGS_IN_FLAC_FILE) + { + Id3tag_Write_File_Tag(ETFile); + }else + { + // Delete the ID3 tags (create a dummy ETFile for the Id3tag_... function) + ET_File *ETFile_tmp = ET_File_Item_New(); + File_Name *FileName_tmp = ET_File_Name_Item_New(); + File_Tag *FileTag_tmp = ET_File_Tag_Item_New(); + // Same file... + FileName_tmp->value = g_strdup(filename); + FileName_tmp->value_utf8 = g_strdup(filename_utf8); // Not necessary to fill 'value_ck' + ETFile_tmp->FileNameList = g_list_append(NULL,FileName_tmp); + ETFile_tmp->FileNameCur = ETFile_tmp->FileNameList; + // With empty tag... + ETFile_tmp->FileTagList = g_list_append(NULL,FileTag_tmp); + ETFile_tmp->FileTag = ETFile_tmp->FileTagList; + Id3tag_Write_File_Tag(ETFile_tmp); + ET_Free_File_List_Item(ETFile_tmp); + } +#endif + + return TRUE; +} + + +#endif /* ENABLE_FLAC */ -- cgit v1.2.3