1 /* EasyTAG - tag editor for audio files
2  * Copyright (C) 2014,2015  David King <amigadave@amigadave.com>
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the Free
6  * Software Foundation; either version 2 of the License, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc., 51
16  * Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 
19 #include "file_tag.h"
20 
21 #include "misc.h"
22 
23 /*
24  * Create a new File_Tag structure.
25  */
26 File_Tag *
et_file_tag_new(void)27 et_file_tag_new (void)
28 {
29     File_Tag *file_tag;
30 
31     file_tag = g_slice_new0 (File_Tag);
32     file_tag->key = et_undo_key_new ();
33 
34     return file_tag;
35 }
36 
37 /*
38  * Frees the list of 'other' field in a File_Tag item (contains attached gchar data).
39  */
40 static void
et_file_tag_free_other_field(File_Tag * file_tag)41 et_file_tag_free_other_field (File_Tag *file_tag)
42 {
43     g_list_free_full (file_tag->other, g_free);
44     file_tag->other = NULL;
45 }
46 
47 
48 /*
49  * Frees a File_Tag item.
50  */
51 void
et_file_tag_free(File_Tag * FileTag)52 et_file_tag_free (File_Tag *FileTag)
53 {
54     g_return_if_fail (FileTag != NULL);
55 
56     g_free(FileTag->title);
57     g_free(FileTag->artist);
58     g_free(FileTag->album_artist);
59     g_free(FileTag->album);
60     g_free(FileTag->disc_number);
61     g_free (FileTag->disc_total);
62     g_free(FileTag->year);
63     g_free(FileTag->track);
64     g_free(FileTag->track_total);
65     g_free(FileTag->genre);
66     g_free(FileTag->comment);
67     g_free(FileTag->composer);
68     g_free(FileTag->orig_artist);
69     g_free(FileTag->copyright);
70     g_free(FileTag->url);
71     g_free(FileTag->encoded_by);
72     et_file_tag_set_picture (FileTag, NULL);
73     et_file_tag_free_other_field (FileTag);
74 
75     g_slice_free (File_Tag, FileTag);
76 }
77 
78 /*
79  * Duplicate the 'other' list, preserving the list already in @destination.
80  */
81 void
et_file_tag_copy_other_into(File_Tag * destination,const File_Tag * source)82 et_file_tag_copy_other_into (File_Tag *destination,
83                              const File_Tag *source)
84 {
85     GList *l;
86     GList *new_other = NULL;
87 
88     for (l = source->other; l != NULL; l = g_list_next (l))
89     {
90         new_other = g_list_prepend (new_other, g_strdup ((gchar *)l->data));
91     }
92 
93     new_other = g_list_reverse (new_other);
94     destination->other = g_list_concat (destination->other, new_other);
95 }
96 
97 
98 /*
99  * Copy data of the File_Tag structure (of ETFile) to the FileTag item.
100  * Reallocate data if not null.
101  */
102 void
et_file_tag_copy_into(File_Tag * destination,const File_Tag * source)103 et_file_tag_copy_into (File_Tag *destination,
104                        const File_Tag *source)
105 {
106     g_return_if_fail (source != NULL);
107     g_return_if_fail (destination != NULL);
108 
109     /* Key for the item, may be overwritten. */
110     destination->key = et_undo_key_new ();
111 
112     et_file_tag_set_title (destination, source->title);
113     et_file_tag_set_artist (destination, source->artist);
114     et_file_tag_set_album_artist (destination, source->album_artist);
115     et_file_tag_set_album (destination, source->album);
116     et_file_tag_set_disc_number (destination, source->disc_number);
117     et_file_tag_set_disc_total (destination, source->disc_total);
118     et_file_tag_set_year (destination, source->year);
119     et_file_tag_set_track_number (destination, source->track);
120     et_file_tag_set_track_total (destination, source->track_total);
121     et_file_tag_set_genre (destination, source->genre);
122     et_file_tag_set_comment (destination, source->comment);
123     et_file_tag_set_composer (destination, source->composer);
124     et_file_tag_set_orig_artist (destination, source->orig_artist);
125     et_file_tag_set_copyright (destination, source->copyright);
126     et_file_tag_set_url (destination, source->url);
127     et_file_tag_set_encoded_by (destination, source->encoded_by);
128     et_file_tag_set_picture (destination, source->picture);
129 
130     if (source->other)
131     {
132         et_file_tag_copy_other_into (destination, source);
133     }
134     else
135     {
136         et_file_tag_free_other_field (destination);
137     }
138 }
139 
140 /*
141  * Set the value of a field of a FileTag item (for ex, value of FileTag->title)
142  * Must be used only for the 'gchar *' components
143  */
144 static void
et_file_tag_set_field(gchar ** FileTagField,const gchar * value)145 et_file_tag_set_field (gchar **FileTagField,
146                        const gchar *value)
147 {
148     g_return_if_fail (FileTagField != NULL);
149 
150     if (*FileTagField != NULL)
151     {
152         g_free (*FileTagField);
153         *FileTagField = NULL;
154     }
155 
156     if (value != NULL)
157     {
158         if (*value != '\0')
159         {
160             *FileTagField = g_strdup (value);
161         }
162     }
163 }
164 
165 void
et_file_tag_set_title(File_Tag * file_tag,const gchar * title)166 et_file_tag_set_title (File_Tag *file_tag,
167                        const gchar *title)
168 {
169     g_return_if_fail (file_tag != NULL);
170 
171     et_file_tag_set_field (&file_tag->title, title);
172 }
173 
174 void
et_file_tag_set_artist(File_Tag * file_tag,const gchar * artist)175 et_file_tag_set_artist (File_Tag *file_tag,
176                         const gchar *artist)
177 {
178     g_return_if_fail (file_tag != NULL);
179 
180     et_file_tag_set_field (&file_tag->artist, artist);
181 }
182 
183 void
et_file_tag_set_album_artist(File_Tag * file_tag,const gchar * album_artist)184 et_file_tag_set_album_artist (File_Tag *file_tag,
185                               const gchar *album_artist)
186 {
187     g_return_if_fail (file_tag != NULL);
188 
189     et_file_tag_set_field (&file_tag->album_artist, album_artist);
190 }
191 
192 void
et_file_tag_set_album(File_Tag * file_tag,const gchar * album)193 et_file_tag_set_album (File_Tag *file_tag,
194                        const gchar *album)
195 {
196     g_return_if_fail (file_tag != NULL);
197 
198     et_file_tag_set_field (&file_tag->album, album);
199 }
200 
201 void
et_file_tag_set_disc_number(File_Tag * file_tag,const gchar * disc_number)202 et_file_tag_set_disc_number (File_Tag *file_tag,
203                              const gchar *disc_number)
204 {
205     g_return_if_fail (file_tag != NULL);
206 
207     et_file_tag_set_field (&file_tag->disc_number, disc_number);
208 }
209 
210 void
et_file_tag_set_disc_total(File_Tag * file_tag,const gchar * disc_total)211 et_file_tag_set_disc_total (File_Tag *file_tag,
212                             const gchar *disc_total)
213 {
214     g_return_if_fail (file_tag != NULL);
215 
216     et_file_tag_set_field (&file_tag->disc_total, disc_total);
217 }
218 
219 void
et_file_tag_set_year(File_Tag * file_tag,const gchar * year)220 et_file_tag_set_year (File_Tag *file_tag,
221                       const gchar *year)
222 {
223     g_return_if_fail (file_tag != NULL);
224 
225     et_file_tag_set_field (&file_tag->year, year);
226 }
227 
228 void
et_file_tag_set_track_number(File_Tag * file_tag,const gchar * track_number)229 et_file_tag_set_track_number (File_Tag *file_tag,
230                               const gchar *track_number)
231 {
232     g_return_if_fail (file_tag != NULL);
233 
234     et_file_tag_set_field (&file_tag->track, track_number);
235 }
236 
237 void
et_file_tag_set_track_total(File_Tag * file_tag,const gchar * track_total)238 et_file_tag_set_track_total (File_Tag *file_tag,
239                              const gchar *track_total)
240 {
241     g_return_if_fail (file_tag != NULL);
242 
243     et_file_tag_set_field (&file_tag->track_total, track_total);
244 }
245 
246 void
et_file_tag_set_genre(File_Tag * file_tag,const gchar * genre)247 et_file_tag_set_genre (File_Tag *file_tag,
248                        const gchar *genre)
249 {
250     g_return_if_fail (file_tag != NULL);
251 
252     et_file_tag_set_field (&file_tag->genre, genre);
253 }
254 
255 void
et_file_tag_set_comment(File_Tag * file_tag,const gchar * comment)256 et_file_tag_set_comment (File_Tag *file_tag,
257                          const gchar *comment)
258 {
259     g_return_if_fail (file_tag != NULL);
260 
261     et_file_tag_set_field (&file_tag->comment, comment);
262 }
263 
264 void
et_file_tag_set_composer(File_Tag * file_tag,const gchar * composer)265 et_file_tag_set_composer (File_Tag *file_tag,
266                           const gchar *composer)
267 {
268     g_return_if_fail (file_tag != NULL);
269 
270     et_file_tag_set_field (&file_tag->composer, composer);
271 }
272 
273 void
et_file_tag_set_orig_artist(File_Tag * file_tag,const gchar * orig_artist)274 et_file_tag_set_orig_artist (File_Tag *file_tag,
275                              const gchar *orig_artist)
276 {
277     g_return_if_fail (file_tag != NULL);
278 
279     et_file_tag_set_field (&file_tag->orig_artist, orig_artist);
280 }
281 
282 void
et_file_tag_set_copyright(File_Tag * file_tag,const gchar * copyright)283 et_file_tag_set_copyright (File_Tag *file_tag,
284                            const gchar *copyright)
285 {
286     g_return_if_fail (file_tag != NULL);
287 
288     et_file_tag_set_field (&file_tag->copyright, copyright);
289 }
290 
291 void
et_file_tag_set_url(File_Tag * file_tag,const gchar * url)292 et_file_tag_set_url (File_Tag *file_tag,
293                      const gchar *url)
294 {
295     g_return_if_fail (file_tag != NULL);
296 
297     et_file_tag_set_field (&file_tag->url, url);
298 }
299 
300 void
et_file_tag_set_encoded_by(File_Tag * file_tag,const gchar * encoded_by)301 et_file_tag_set_encoded_by (File_Tag *file_tag,
302                             const gchar *encoded_by)
303 {
304     g_return_if_fail (file_tag != NULL);
305 
306     et_file_tag_set_field (&file_tag->encoded_by, encoded_by);
307 }
308 
309 /*
310  * et_file_tag_set_picture:
311  * @file_tag: the #File_Tag on which to set the image
312  * @pic: the image to set
313  *
314  * Set the images inside @file_tag to be @pic, freeing existing images as
315  * necessary. Copies @pic with et_picture_copy_all().
316  */
317 void
et_file_tag_set_picture(File_Tag * file_tag,const EtPicture * pic)318 et_file_tag_set_picture (File_Tag *file_tag,
319                          const EtPicture *pic)
320 {
321     g_return_if_fail (file_tag != NULL);
322 
323     if (file_tag->picture != NULL)
324     {
325         et_picture_free (file_tag->picture);
326         file_tag->picture = NULL;
327     }
328 
329     if (pic)
330     {
331         file_tag->picture = et_picture_copy_all (pic);
332     }
333 }
334 
335 /*
336  * Compares two File_Tag items and returns TRUE if there aren't the same.
337  * Notes:
338  *  - if field is '' or NULL => will be removed
339  */
340 gboolean
et_file_tag_detect_difference(const File_Tag * FileTag1,const File_Tag * FileTag2)341 et_file_tag_detect_difference (const File_Tag *FileTag1,
342                                const File_Tag *FileTag2)
343 {
344     const EtPicture *pic1;
345     const EtPicture *pic2;
346 
347     g_return_val_if_fail (FileTag1 != NULL && FileTag2 != NULL, FALSE);
348 
349     if ( ( FileTag1 && !FileTag2)
350       || (!FileTag1 &&  FileTag2) )
351         return TRUE;
352 
353     /* Title */
354     if (et_normalized_strcmp0 (FileTag1->title, FileTag2->title) != 0)
355     {
356         return TRUE;
357     }
358 
359     /* Artist */
360     if (et_normalized_strcmp0 (FileTag1->artist, FileTag2->artist) != 0)
361     {
362         return TRUE;
363     }
364 
365 	/* Album Artist */
366     if (et_normalized_strcmp0 (FileTag1->album_artist,
367                                FileTag2->album_artist) != 0)
368     {
369         return TRUE;
370     }
371 
372     /* Album */
373     if (et_normalized_strcmp0 (FileTag1->album, FileTag2->album) != 0)
374     {
375         return TRUE;
376     }
377 
378     /* Disc Number */
379     if (et_normalized_strcmp0 (FileTag1->disc_number,
380                                FileTag2->disc_number) != 0)
381     {
382         return TRUE;
383     }
384 
385     /* Discs Total */
386     if (et_normalized_strcmp0 (FileTag1->disc_total,
387                                FileTag2->disc_total) != 0)
388     {
389         return TRUE;
390     }
391 
392     /* Year */
393     if (et_normalized_strcmp0 (FileTag1->year, FileTag2->year) != 0)
394     {
395         return TRUE;
396     }
397 
398     /* Track */
399     if (et_normalized_strcmp0 (FileTag1->track, FileTag2->track) != 0)
400     {
401         return TRUE;
402     }
403 
404     /* Track Total */
405     if (et_normalized_strcmp0 (FileTag1->track_total,
406                                FileTag2->track_total) != 0)
407     {
408         return TRUE;
409     }
410 
411     /* Genre */
412     if (et_normalized_strcmp0 (FileTag1->genre, FileTag2->genre) != 0)
413     {
414         return TRUE;
415     }
416 
417     /* Comment */
418     if (et_normalized_strcmp0 (FileTag1->comment, FileTag2->comment) != 0)
419     {
420         return TRUE;
421     }
422 
423     /* Composer */
424     if (et_normalized_strcmp0 (FileTag1->composer, FileTag2->composer) != 0)
425     {
426         return TRUE;
427     }
428 
429     /* Original artist */
430     if (et_normalized_strcmp0 (FileTag1->orig_artist,
431                                FileTag2->orig_artist) != 0)
432     {
433         return TRUE;
434     }
435 
436     /* Copyright */
437     if (et_normalized_strcmp0 (FileTag1->copyright, FileTag2->copyright) != 0)
438     {
439         return TRUE;
440     }
441 
442     /* URL */
443     if (et_normalized_strcmp0 (FileTag1->url, FileTag2->url) != 0)
444     {
445         return TRUE;
446     }
447 
448     /* Encoded by */
449     if (et_normalized_strcmp0 (FileTag1->encoded_by,
450                                FileTag2->encoded_by) != 0)
451     {
452         return TRUE;
453     }
454 
455     /* Picture */
456     for (pic1 = FileTag1->picture, pic2 = FileTag2->picture;
457          pic1 || pic2;
458          pic1 = pic1->next, pic2 = pic2->next)
459     {
460         if (et_picture_detect_difference (pic1, pic2))
461         {
462             return TRUE;
463         }
464     }
465 
466     return FALSE; /* No changes */
467 }
468