add callback-based versions of chain writing: FLAC__metadata_chain_check_if_tempfile_...
[flac.git] / src / plugin_common / canonical_tag.c
1 /* plugin_common - Routines common to several plugins
2  * Copyright (C) 2002,2003,2004  Josh Coalson
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21
22 #include "canonical_tag.h"
23 #include "id3v2.h"
24 #include "vorbiscomment.h"
25 #include "FLAC/assert.h"
26 #include "FLAC/metadata.h"
27
28 static void local__safe_free(void *object)
29 {
30         if(0 != object)
31                 free(object);
32 }
33
34 static void local__copy_field(char **dest, const char *src, unsigned n)
35 {
36         if(n > 0) {
37                 const char *p = src + n;
38                 while(p > src && *(--p) == ' ')
39                         ;
40                 n = p - src + 1;
41                 if(0 != (*dest = malloc(n+1))) {
42                         memcpy(*dest, src, n);
43                         (*dest)[n] = '\0';
44                 }
45         }
46         else
47                 *dest = 0;
48 }
49
50 static FLAC__bool local__get_id3v1_tag_as_canonical(const char *filename, FLAC_Plugin__CanonicalTag *tag)
51 {
52         FLAC_Plugin__Id3v1_Tag id3v1_tag;
53
54         if(FLAC_plugin__id3v1_tag_get(filename, &id3v1_tag)) {
55                 FLAC_plugin__canonical_tag_convert_from_id3v1(tag, &id3v1_tag);
56                 return true;
57         }
58         return false;
59 }
60
61 FLAC_Plugin__CanonicalTag *FLAC_plugin__canonical_tag_new()
62 {
63         FLAC_Plugin__CanonicalTag *object = (FLAC_Plugin__CanonicalTag*)malloc(sizeof(FLAC_Plugin__CanonicalTag));
64         if(0 != object)
65                 FLAC_plugin__canonical_tag_init(object);
66         return object;
67 }
68
69 void FLAC_plugin__canonical_tag_delete(FLAC_Plugin__CanonicalTag *object)
70 {
71         FLAC__ASSERT(0 != object);
72         FLAC_plugin__canonical_tag_clear(object);
73         free(object);
74 }
75
76 void FLAC_plugin__canonical_tag_init(FLAC_Plugin__CanonicalTag *object)
77 {
78         FLAC__ASSERT(0 != object);
79         object->title = 0;
80         object->composer = 0;
81         object->performer = 0;
82         object->album = 0;
83         object->year_recorded = 0;
84         object->year_performed = 0;
85         object->track_number = 0;
86         object->tracks_in_album = 0;
87         object->genre = 0;
88         object->comment = 0;
89 }
90
91 void FLAC_plugin__canonical_tag_clear(FLAC_Plugin__CanonicalTag *object)
92 {
93         FLAC__ASSERT(0 != object);
94         local__safe_free(object->title);
95         local__safe_free(object->composer);
96         local__safe_free(object->performer);
97         local__safe_free(object->album);
98         local__safe_free(object->year_recorded);
99         local__safe_free(object->year_performed);
100         local__safe_free(object->track_number);
101         local__safe_free(object->tracks_in_album);
102         local__safe_free(object->genre);
103         local__safe_free(object->comment);
104         FLAC_plugin__canonical_tag_init(object);
105 }
106
107 static void local__grab(char **dest, char **src)
108 {
109         if(0 == *dest) {
110                 *dest = *src;
111                 *src = 0;
112         }
113 }
114
115 void FLAC_plugin__canonical_tag_merge(FLAC_Plugin__CanonicalTag *dest, FLAC_Plugin__CanonicalTag *src)
116 {
117         local__grab(&dest->title, &src->title);
118         local__grab(&dest->composer, &src->composer);
119         local__grab(&dest->performer, &src->performer);
120         local__grab(&dest->album, &src->album);
121         local__grab(&dest->year_recorded, &src->year_recorded);
122         local__grab(&dest->year_performed, &src->year_performed);
123         local__grab(&dest->track_number, &src->track_number);
124         local__grab(&dest->tracks_in_album, &src->tracks_in_album);
125         local__grab(&dest->genre, &src->genre);
126         local__grab(&dest->comment, &src->comment);
127 }
128
129 void FLAC_plugin__canonical_tag_convert_from_id3v1(FLAC_Plugin__CanonicalTag *object, const FLAC_Plugin__Id3v1_Tag *id3v1_tag)
130 {
131         local__copy_field(&object->title, id3v1_tag->title, 30);
132         local__copy_field(&object->composer, id3v1_tag->artist, 30);
133         local__copy_field(&object->performer, id3v1_tag->artist, 30);
134         local__copy_field(&object->album, id3v1_tag->album, 30);
135         local__copy_field(&object->year_performed, id3v1_tag->year, 4);
136
137         /* Check for v1.1 tags. */
138         if (id3v1_tag->comment.v1_1.zero == 0) {
139                 if(0 != (object->track_number = malloc(4)))
140                         sprintf(object->track_number, "%u", (unsigned)id3v1_tag->comment.v1_1.track);
141                 local__copy_field(&object->comment, id3v1_tag->comment.v1_1.comment, 28);
142         }
143         else {
144                 object->track_number = strdup("0");
145                 local__copy_field(&object->comment, id3v1_tag->comment.v1_0.comment, 30);
146         }
147
148         object->genre = strdup(FLAC_plugin__id3v1_tag_get_genre_as_string(id3v1_tag->genre));
149 }
150
151 void FLAC_plugin__canonical_tag_get_combined(const char *filename, FLAC_Plugin__CanonicalTag *tag)
152 {
153         FLAC_Plugin__CanonicalTag id3v1_tag, id3v2_tag;
154
155         FLAC_plugin__vorbiscomment_get(filename, tag);
156
157         FLAC_plugin__canonical_tag_init(&id3v2_tag);
158         (void)FLAC_plugin__id3v2_tag_get(filename, &id3v2_tag);
159
160         FLAC_plugin__canonical_tag_init(&id3v1_tag);
161         (void)local__get_id3v1_tag_as_canonical(filename, &id3v1_tag);
162
163         /* merge tags, preferring, in order: vorbis comments, id3v2, id3v1 */
164         FLAC_plugin__canonical_tag_merge(tag, &id3v2_tag);
165         FLAC_plugin__canonical_tag_merge(tag, &id3v1_tag);
166
167         FLAC_plugin__canonical_tag_clear(&id3v1_tag);
168         FLAC_plugin__canonical_tag_clear(&id3v2_tag);
169 }