/* * Read tag data from a FLAC file using the level 2 flac interface, * Note: * - if field is found but contains no info (strlen(str)==0), we don't read it */ gboolean flac_tag_read_file_tag (GFile *file, File_Tag *FileTag, GError **error) { FLAC__Metadata_Chain *chain; EtFlacReadState state; FLAC__IOCallbacks callbacks = { et_flac_read_func, NULL, /* Do not set a write callback. */ et_flac_seek_func, et_flac_tell_func, et_flac_eof_func, et_flac_read_close_func }; FLAC__Metadata_Iterator *iter; EtPicture *prev_pic = NULL; g_return_val_if_fail (file != NULL && FileTag != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); chain = FLAC__metadata_chain_new (); if (chain == NULL) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOMEM, "%s", g_strerror (ENOMEM)); return FALSE; } state.error = NULL; state.istream = g_file_read (file, NULL, &state.error); state.seekable = G_SEEKABLE (state.istream); if (!FLAC__metadata_chain_read_with_callbacks (chain, &state, callbacks)) { /* TODO: Provide a dedicated error enum corresponding to status. */ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "%s", _("Error opening FLAC file")); et_flac_read_close_func (&state); return FALSE; } iter = FLAC__metadata_iterator_new (); if (iter == NULL) { et_flac_read_close_func (&state); g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOMEM, "%s", g_strerror (ENOMEM)); return FALSE; } FLAC__metadata_iterator_init (iter, chain); while (FLAC__metadata_iterator_next (iter)) { FLAC__StreamMetadata *block; block = FLAC__metadata_iterator_get_block (iter); if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { const FLAC__StreamMetadata_VorbisComment *vc; GHashTable *tags; GSList *strings; GHashTableIter tags_iter; gchar *key; /* Get comments from block. */ vc = &block->data.vorbis_comment; tags = populate_tag_hash_table (vc); /* Title */ if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_TITLE))) { g_slist_foreach (strings, values_list_foreach, &FileTag->title); g_slist_free (strings); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_TITLE); } /* Artist */ if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_ARTIST))) { g_slist_foreach (strings, values_list_foreach, &FileTag->artist); g_slist_free (strings); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_ARTIST); } /* Album artist. */ if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_ALBUM_ARTIST))) { g_slist_foreach (strings, values_list_foreach, &FileTag->album_artist); g_slist_free (strings); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_ALBUM_ARTIST); } /* Album. */ if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_ALBUM))) { g_slist_foreach (strings, values_list_foreach, &FileTag->album); g_slist_free (strings); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_ALBUM); } /* Disc number and total discs. */ if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_DISC_TOTAL))) { /* Only take values from the first total discs field. */ if (!et_str_empty (strings->data)) { FileTag->disc_total = et_disc_number_to_string (atoi (strings->data)); } g_slist_free_full (strings, g_free); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_DISC_TOTAL); } if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_DISC_NUMBER))) { /* Only take values from the first disc number field. */ if (!et_str_empty (strings->data)) { gchar *separator; separator = strchr (strings->data, '/'); if (separator && !FileTag->disc_total) { FileTag->disc_total = et_disc_number_to_string (atoi (separator + 1)); *separator = '\0'; } FileTag->disc_number = et_disc_number_to_string (atoi (strings->data)); } g_slist_free_full (strings, g_free); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_DISC_NUMBER); } /* Track number and total tracks. */ if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_TRACK_TOTAL))) { /* Only take values from the first total tracks field. */ if (!et_str_empty (strings->data)) { FileTag->track_total = et_track_number_to_string (atoi (strings->data)); } g_slist_free_full (strings, g_free); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_TRACK_TOTAL); } if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_TRACK_NUMBER))) { /* Only take values from the first track number field. */ if (!et_str_empty (strings->data)) { gchar *separator; separator = strchr (strings->data, '/'); if (separator && !FileTag->track_total) { FileTag->track_total = et_track_number_to_string (atoi (separator + 1)); *separator = '\0'; } FileTag->track = et_track_number_to_string (atoi (strings->data)); } g_slist_free_full (strings, g_free); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_TRACK_NUMBER); } /* Year. */ if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_DATE))) { g_slist_foreach (strings, values_list_foreach, &FileTag->year); g_slist_free (strings); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_DATE); } /* Genre. */ if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_GENRE))) { g_slist_foreach (strings, values_list_foreach, &FileTag->genre); g_slist_free (strings); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_GENRE); } /* Comment. */ { GSList *descs; GSList *comments; descs = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_DESCRIPTION); comments = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_COMMENT); /* Prefer DESCRIPTION, as it is part of the spec. */ if (descs && !comments) { g_slist_foreach (descs, values_list_foreach, &FileTag->comment); } else if (descs && comments) { /* Mark the file as modified, so that comments are written * to the DESCRIPTION field on saving. */ FileTag->saved = FALSE; g_slist_foreach (descs, values_list_foreach, &FileTag->comment); g_slist_foreach (comments, values_list_foreach, &FileTag->comment); } else if (comments) { FileTag->saved = FALSE; g_slist_foreach (comments, values_list_foreach, &FileTag->comment); } g_slist_free (descs); g_slist_free (comments); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_DESCRIPTION); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_COMMENT); } /* Composer. */ if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_COMPOSER))) { g_slist_foreach (strings, values_list_foreach, &FileTag->composer); g_slist_free (strings); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_COMPOSER); } /* Original artist. */ if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_PERFORMER))) { g_slist_foreach (strings, values_list_foreach, &FileTag->orig_artist); g_slist_free (strings); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_PERFORMER); } /* Copyright. */ if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_COPYRIGHT))) { g_slist_foreach (strings, values_list_foreach, &FileTag->copyright); g_slist_free (strings); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_COPYRIGHT); } /* URL. */ if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_CONTACT))) { g_slist_foreach (strings, values_list_foreach, &FileTag->url); g_slist_free (strings); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_CONTACT); } /* Encoded by. */ if ((strings = g_hash_table_lookup (tags, ET_VORBIS_COMMENT_FIELD_ENCODED_BY))) { g_slist_foreach (strings, values_list_foreach, &FileTag->encoded_by); g_slist_free (strings); g_hash_table_remove (tags, ET_VORBIS_COMMENT_FIELD_ENCODED_BY); } /* Save unsupported fields. */ g_hash_table_iter_init (&tags_iter, tags); while (g_hash_table_iter_next (&tags_iter, (gpointer *)&key, (gpointer *)&strings)) { GSList *l; for (l = strings; l != NULL; l = g_slist_next (l)) { FileTag->other = g_list_prepend (FileTag->other, g_strconcat (key, "=", l->data, NULL)); } g_slist_free_full (strings, g_free); g_hash_table_iter_remove (&tags_iter); } if (FileTag->other) { FileTag->other = g_list_reverse (FileTag->other); } /* The hash table should now only contain keys. */ g_hash_table_unref (tags); } else if (block->type == FLAC__METADATA_TYPE_PICTURE) { /* Picture. */ const FLAC__StreamMetadata_Picture *p; GBytes *bytes; EtPicture *pic; /* Get picture data from block. */ p = &block->data.picture; bytes = g_bytes_new (p->data, p->data_length); pic = et_picture_new (p->type, (const gchar *)p->description, 0, 0, bytes); g_bytes_unref (bytes); if (!prev_pic) { FileTag->picture = pic; } else { prev_pic->next = pic; } prev_pic = pic; } } FLAC__metadata_iterator_delete (iter); FLAC__metadata_chain_delete (chain); et_flac_read_close_func (&state); #ifdef ENABLE_MP3 /* If no FLAC vorbis tag found : we try to get the ID3 tag if it exists * (but it will be deleted when rewriting the tag) */ if ( FileTag->title == NULL && FileTag->artist == NULL && FileTag->album_artist == NULL && FileTag->album == NULL && FileTag->disc_number == NULL && FileTag->disc_total == 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->picture == NULL) { id3tag_read_file_tag (file, FileTag, NULL); // 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_artist != NULL || FileTag->album != NULL || FileTag->disc_number != NULL || FileTag->disc_total != 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->picture != NULL) { FileTag->saved = FALSE; } } #endif return TRUE; }
/* * Read tag data from a Wavpack file. */ gboolean Wavpack_Tag_Read_File_Tag (gchar *filename, File_Tag *FileTag) { WavpackContext *wpc; gchar *field, *field2; guint length; int open_flags = OPEN_TAGS; g_return_val_if_fail (filename != NULL && FileTag != NULL, FALSE); wpc = WavpackOpenFileInput(filename, NULL, open_flags, 0); if ( wpc == NULL ) { return FALSE; } /* * Title */ field = g_malloc0(sizeof(char) * MAXLEN); length = WavpackGetTagItem(wpc, "title", field, MAXLEN); if ( length > 0 && FileTag->title == NULL ) { FileTag->title = Try_To_Validate_Utf8_String(field); } g_free (field); /* * Artist */ field = g_malloc0(sizeof(char) * MAXLEN); length = WavpackGetTagItem(wpc, "artist", field, MAXLEN); if ( length > 0 && FileTag->artist == NULL) { FileTag->artist = Try_To_Validate_Utf8_String(field); } g_free (field); /* * Album */ field = g_malloc0(sizeof(char) * MAXLEN); length = WavpackGetTagItem(wpc, "album", field, MAXLEN); if ( length > 0 && FileTag->album == NULL ) { FileTag->album = Try_To_Validate_Utf8_String(field); } g_free (field); /* * Discnumber + Disctotal. */ field = g_malloc0 (sizeof (char) * MAXLEN); length = WavpackGetTagItem (wpc, "part", field, MAXLEN); field2 = g_utf8_strchr (field, -1, '/'); /* Need to cut off the total tracks if present */ if (field2) { *field2 = 0; field2++; } if (field2 && FileTag->disc_total == NULL) { FileTag->disc_total = et_disc_number_to_string (atoi (Try_To_Validate_Utf8_String (field2))); } if (length > 0 && FileTag->disc_number == NULL) { FileTag->disc_number = et_disc_number_to_string (atoi (Try_To_Validate_Utf8_String (field))); } g_free (field); /* * Year */ field = g_malloc0(sizeof(char) * MAXLEN); length = WavpackGetTagItem(wpc, "year", field, MAXLEN); if ( length > 0 && FileTag->year == NULL ) { FileTag->year = Try_To_Validate_Utf8_String(field); } g_free (field); /* * Tracknumber + tracktotal */ field = g_malloc0(sizeof(char) * MAXLEN); length = WavpackGetTagItem(wpc, "track", field, MAXLEN); field2 = g_utf8_strchr(field, -1, '/'); /* Need to cut off the total tracks if present */ if (field2) { *field2 = 0; field2++; } if (field2 && FileTag->track_total == NULL) { FileTag->track_total = et_track_number_to_string (atoi (Try_To_Validate_Utf8_String (field2))); } if (length > 0 && FileTag->track == NULL) { FileTag->track = et_track_number_to_string (atoi (Try_To_Validate_Utf8_String (field))); } g_free (field); /* * Genre */ field = g_malloc0(sizeof(char) * MAXLEN); length = WavpackGetTagItem(wpc, "genre", field, MAXLEN); if ( length > 0 && FileTag->genre == NULL ) { FileTag->genre = Try_To_Validate_Utf8_String(field); } g_free (field); /* * Comment */ field = g_malloc0(sizeof(char) * MAXLEN); length = WavpackGetTagItem(wpc, "comment", field, MAXLEN); if ( length > 0 && FileTag->comment == NULL ) { FileTag->comment = Try_To_Validate_Utf8_String(field); } g_free (field); /* * Composer */ field = g_malloc0(sizeof(char) * MAXLEN); length = WavpackGetTagItem(wpc, "composer", field, MAXLEN); if ( length > 0 && FileTag->composer == NULL ) { FileTag->composer = Try_To_Validate_Utf8_String(field); } g_free (field); /* * Original artist */ field = g_malloc0(sizeof(char) * MAXLEN); length = WavpackGetTagItem(wpc, "original artist", field, MAXLEN); if ( length > 0 && FileTag->orig_artist == NULL ) { FileTag->orig_artist = Try_To_Validate_Utf8_String(field); } g_free (field); /* * Copyright */ field = g_malloc0(sizeof(char) * MAXLEN); length = WavpackGetTagItem(wpc, "copyright", field, MAXLEN); if ( length > 0 && FileTag->copyright == NULL ) { FileTag->copyright = Try_To_Validate_Utf8_String(field); } g_free (field); /* * URL */ field = g_malloc0(sizeof(char) * MAXLEN); length = WavpackGetTagItem(wpc, "copyright url", field, MAXLEN); if ( length > 0 && FileTag->url == NULL ) { FileTag->url = Try_To_Validate_Utf8_String(field); } g_free (field); /* * Encoded by */ field = g_malloc0(sizeof(char) * MAXLEN); length = WavpackGetTagItem(wpc, "encoded by", field, MAXLEN); if ( length > 0 && FileTag->encoded_by == NULL ) { FileTag->encoded_by = Try_To_Validate_Utf8_String(field); } g_free (field); WavpackCloseFile(wpc); return TRUE; }
/* * Read tag data from a Wavpack file. */ gboolean wavpack_tag_read_file_tag (GFile *file, File_Tag *FileTag, GError **error) { WavpackStreamReader reader = { wavpack_read_bytes, wavpack_get_pos, wavpack_set_pos_abs, wavpack_set_pos_rel, wavpack_push_back_byte, wavpack_get_length, wavpack_can_seek, NULL /* No writing. */ }; EtWavpackState state; WavpackContext *wpc; gchar message[80]; gchar field[MAXLEN] = { 0, }; gchar *field2; guint length; const int open_flags = OPEN_TAGS; g_return_val_if_fail (file != NULL && FileTag != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); state.error = NULL; state.istream = g_file_read (file, NULL, &state.error); if (!state.istream) { g_propagate_error (error, state.error); return FALSE; } state.seekable = G_SEEKABLE (state.istream); /* NULL for the WavPack correction file. */ wpc = WavpackOpenFileInputEx (&reader, &state, NULL, message, open_flags, 0); if (wpc == NULL) { if (state.error) { g_propagate_error (error, state.error); } else { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "%s", message); } g_object_unref (state.istream); return FALSE; } /* * Title */ length = WavpackGetTagItem(wpc, "title", field, MAXLEN); if ( length > 0 && FileTag->title == NULL ) { FileTag->title = Try_To_Validate_Utf8_String(field); } memset (field, '\0', MAXLEN); /* * Artist */ length = WavpackGetTagItem(wpc, "artist", field, MAXLEN); if ( length > 0 && FileTag->artist == NULL) { FileTag->artist = Try_To_Validate_Utf8_String(field); } memset (field, '\0', MAXLEN); /* Album artist. */ length = WavpackGetTagItem (wpc, "album artist", field, MAXLEN); if (length > 0 && FileTag->album_artist == NULL) { FileTag->album_artist = Try_To_Validate_Utf8_String (field); } memset (field, '\0', MAXLEN); /* * Album */ length = WavpackGetTagItem(wpc, "album", field, MAXLEN); if ( length > 0 && FileTag->album == NULL ) { FileTag->album = Try_To_Validate_Utf8_String(field); } memset (field, '\0', MAXLEN); /* * Discnumber + Disctotal. */ length = WavpackGetTagItem (wpc, "part", field, MAXLEN); field2 = strchr (field, '/'); /* Need to cut off the total tracks if present */ if (field2) { *field2 = 0; field2++; } if (field2 && FileTag->disc_total == NULL) { gchar *tmp; tmp = Try_To_Validate_Utf8_String (field2); FileTag->disc_total = et_disc_number_to_string (atoi (tmp)); g_free (tmp); } if (length > 0 && FileTag->disc_number == NULL) { gchar *tmp; tmp = Try_To_Validate_Utf8_String (field); FileTag->disc_number = et_disc_number_to_string (atoi (tmp)); g_free (tmp); } memset (field, '\0', MAXLEN); /* * Year */ length = WavpackGetTagItem(wpc, "year", field, MAXLEN); if ( length > 0 && FileTag->year == NULL ) { FileTag->year = Try_To_Validate_Utf8_String(field); } memset (field, '\0', MAXLEN); /* * Tracknumber + tracktotal */ length = WavpackGetTagItem(wpc, "track", field, MAXLEN); field2 = strchr (field, '/'); /* Need to cut off the total tracks if present */ if (field2) { *field2 = 0; field2++; } if (field2 && FileTag->track_total == NULL) { gchar *tmp; tmp = Try_To_Validate_Utf8_String (field2); FileTag->track_total = et_track_number_to_string (atoi (tmp)); g_free (tmp); } if (length > 0 && FileTag->track == NULL) { gchar *tmp; tmp = Try_To_Validate_Utf8_String (field); FileTag->track = et_track_number_to_string (atoi (tmp)); g_free (tmp); } memset (field, '\0', MAXLEN); /* * Genre */ length = WavpackGetTagItem(wpc, "genre", field, MAXLEN); if ( length > 0 && FileTag->genre == NULL ) { FileTag->genre = Try_To_Validate_Utf8_String(field); } memset (field, '\0', MAXLEN); /* * Comment */ length = WavpackGetTagItem(wpc, "comment", field, MAXLEN); if ( length > 0 && FileTag->comment == NULL ) { FileTag->comment = Try_To_Validate_Utf8_String(field); } memset (field, '\0', MAXLEN); /* * Composer */ length = WavpackGetTagItem(wpc, "composer", field, MAXLEN); if ( length > 0 && FileTag->composer == NULL ) { FileTag->composer = Try_To_Validate_Utf8_String(field); } memset (field, '\0', MAXLEN); /* * Original artist */ length = WavpackGetTagItem(wpc, "original artist", field, MAXLEN); if ( length > 0 && FileTag->orig_artist == NULL ) { FileTag->orig_artist = Try_To_Validate_Utf8_String(field); } memset (field, '\0', MAXLEN); /* * Copyright */ length = WavpackGetTagItem(wpc, "copyright", field, MAXLEN); if ( length > 0 && FileTag->copyright == NULL ) { FileTag->copyright = Try_To_Validate_Utf8_String(field); } memset (field, '\0', MAXLEN); /* * URL */ length = WavpackGetTagItem(wpc, "copyright url", field, MAXLEN); if ( length > 0 && FileTag->url == NULL ) { FileTag->url = Try_To_Validate_Utf8_String(field); } memset (field, '\0', MAXLEN); /* * Encoded by */ length = WavpackGetTagItem(wpc, "encoded by", field, MAXLEN); if ( length > 0 && FileTag->encoded_by == NULL ) { FileTag->encoded_by = Try_To_Validate_Utf8_String(field); } WavpackCloseFile(wpc); g_object_unref (state.istream); return TRUE; }