1 /* EasyTAG - Tag editor for audio files
2  * Copyright (C) 2014-2015  David King <amigadave@amigadave.com>
3  * Copyright (C) 2001-2003  Jerome Couderc <easytag@gmail.com>
4  * Copyright (C) 2002-2003  Artur Polaczyñski <artii@o2.pl>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
21 #include "config.h"
22 
23 #include <glib/gi18n.h>
24 #include <glib/gstdio.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 
29 #include "ape_tag.h"
30 #include "et_core.h"
31 #include "misc.h"
32 #include "setting.h"
33 #include "charset.h"
34 #include "libapetag/apetaglib.h"
35 
36 /*************
37  * Functions *
38  *************/
39 
40 /*
41  * set_string_field:
42  * @field: (inout): pointer to a location in which to store the field value
43  * @string: (transfer none): the string to copy and store in @field
44  *
45  * Copy @string and store it in @field, first validating that the string is
46  * valid UTF-8.
47  */
48 static void
set_string_field(gchar ** field,gchar * string)49 set_string_field (gchar **field,
50                   gchar *string)
51 {
52     if (!et_str_empty (string))
53     {
54         if (g_utf8_validate (string, -1, NULL))
55         {
56             *field = g_strdup (string);
57         }
58         else
59         {
60             /* Unnecessarily validates the field again, but this should not be
61              * the common case. */
62             *field = Try_To_Validate_Utf8_String (string);
63         }
64     }
65 }
66 
67 /*
68  * Note:
69  *  - if field is found but contains no info (strlen(str)==0), we don't read it
70  */
71 gboolean
ape_tag_read_file_tag(GFile * file,File_Tag * FileTag,GError ** error)72 ape_tag_read_file_tag (GFile *file,
73                        File_Tag *FileTag,
74                        GError **error)
75 {
76     FILE *fp;
77     gchar *filename;
78     gchar *string = NULL;
79     gchar *string1 = NULL;
80     apetag *ape_cnt;
81 
82     g_return_val_if_fail (file != NULL && FileTag != NULL, FALSE);
83     g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
84 
85     filename = g_file_get_path (file);
86 
87     if ((fp = g_fopen (filename, "rb")) == NULL)
88     {
89         g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
90                      _("Error while opening file: %s"),
91                      g_strerror (errno));
92         g_free (filename);
93         return FALSE;
94     }
95 
96     ape_cnt = apetag_init();
97     apetag_read_fp (ape_cnt, fp, filename, 0); /* read all tags ape,id3v[12]*/
98 
99     g_free (filename);
100 
101     /* Title */
102     string = apefrm_getstr (ape_cnt, APE_TAG_FIELD_TITLE);
103     set_string_field (&FileTag->title, string);
104 
105     /* Artist */
106     string = apefrm_getstr (ape_cnt, APE_TAG_FIELD_ARTIST);
107     set_string_field (&FileTag->artist, string);
108 
109     /* Album artist. */
110     string = apefrm_getstr (ape_cnt, APE_TAG_FIELD_ALBUMARTIST);
111     set_string_field (&FileTag->album_artist, string);
112 
113     /* Album */
114     string = apefrm_getstr (ape_cnt, APE_TAG_FIELD_ALBUM);
115     set_string_field (&FileTag->album, string);
116 
117     /* Disc Number and Disc Total */
118     string = apefrm_getstr (ape_cnt, APE_TAG_FIELD_PART);
119 
120     if (string)
121     {
122         string = Try_To_Validate_Utf8_String (string);
123 
124         string1 = strchr (string, '/');
125 
126         if (string1)
127         {
128             FileTag->disc_total = et_disc_number_to_string (atoi (string1
129                                                                   + 1));
130             *string1 = '\0';
131         }
132 
133         FileTag->disc_number = et_disc_number_to_string (atoi (string));
134 
135         g_free (string);
136     }
137     else
138     {
139         FileTag->disc_number = FileTag->disc_total = NULL;
140     }
141 
142     /* Year */
143     string = apefrm_getstr (ape_cnt, APE_TAG_FIELD_YEAR);
144     set_string_field (&FileTag->year, string);
145 
146     /* Track and Total Track */
147     string = apefrm_getstr (ape_cnt, APE_TAG_FIELD_TRACK);
148 
149     if (string)
150     {
151         string = Try_To_Validate_Utf8_String(string);
152 
153         string1 = strchr (string, '/');
154 
155         if (string1)
156         {
157             FileTag->track_total = et_track_number_to_string (atoi (string1
158                                                                     + 1));
159             *string1 = '\0';
160         }
161         FileTag->track = et_track_number_to_string (atoi (string));
162 
163         g_free(string);
164     } else
165     {
166         FileTag->track = FileTag->track_total = NULL;
167     }
168 
169     /* Genre */
170     string = apefrm_getstr (ape_cnt, APE_TAG_FIELD_GENRE);
171     set_string_field (&FileTag->genre, string);
172 
173     /* Comment */
174     string = apefrm_getstr (ape_cnt, APE_TAG_FIELD_COMMENT);
175     set_string_field (&FileTag->comment, string);
176 
177     /* Composer */
178     string = apefrm_getstr (ape_cnt, APE_TAG_FIELD_COMPOSER);
179     set_string_field (&FileTag->composer, string);
180 
181     /* Original artist */
182     string = apefrm_getstr (ape_cnt, "Original Artist");
183     set_string_field (&FileTag->orig_artist, string);
184 
185     /* Copyright */
186     string = apefrm_getstr (ape_cnt, APE_TAG_FIELD_COPYRIGHT);
187     set_string_field (&FileTag->copyright, string);
188 
189     /* URL */
190     string = apefrm_getstr (ape_cnt, APE_TAG_FIELD_RELATED_URL);
191     set_string_field (&FileTag->url, string);
192 
193     /* Encoded by */
194     string = apefrm_getstr (ape_cnt, "Encoded By");
195     set_string_field (&FileTag->encoded_by, string);
196 
197     apetag_free (ape_cnt);
198     fclose (fp);
199 
200     return TRUE;
201 }
202 
203 gboolean
ape_tag_write_file_tag(const ET_File * ETFile,GError ** error)204 ape_tag_write_file_tag (const ET_File *ETFile,
205                         GError **error)
206 {
207     const File_Tag *FileTag;
208     const gchar *filename_in;
209     //FILE     *file_in;
210     gchar    *string;
211     //GList    *list;
212     apetag   *ape_mem;
213 
214     g_return_val_if_fail (ETFile != NULL && ETFile->FileTag != NULL, FALSE);
215     g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
216 
217     FileTag     = (File_Tag *)ETFile->FileTag->data;
218     filename_in = ((File_Name *)ETFile->FileNameCur->data)->value;
219 
220     ape_mem = apetag_init ();
221 
222     /* TODO: Pointless, as g_set_error() will try to malloc. */
223     if (!ape_mem)
224     {
225         g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOMEM, "%s",
226                      g_strerror (ENOMEM));
227         return FALSE;
228     }
229 
230     /*********
231      * Title *
232      *********/
233     if (!et_str_empty (FileTag->title))
234         apefrm_add(ape_mem, 0, APE_TAG_FIELD_TITLE, FileTag->title);
235     else
236         apefrm_remove(ape_mem,APE_TAG_FIELD_TITLE);
237 
238 
239     /**********
240      * Artist *
241      **********/
242     if (!et_str_empty (FileTag->artist))
243         apefrm_add(ape_mem, 0, APE_TAG_FIELD_ARTIST, FileTag->artist);
244     else
245         apefrm_remove(ape_mem,APE_TAG_FIELD_ARTIST);
246 
247     /* Album artist. */
248     if (!et_str_empty (FileTag->album_artist))
249     {
250         apefrm_add (ape_mem, 0, APE_TAG_FIELD_ALBUMARTIST,
251                     FileTag->album_artist);
252     }
253     else
254     {
255         apefrm_remove (ape_mem, APE_TAG_FIELD_ALBUMARTIST);
256     }
257 
258     /*********
259      * Album *
260      *********/
261     if (!et_str_empty (FileTag->album))
262         apefrm_add(ape_mem, 0, APE_TAG_FIELD_ALBUM, FileTag->album);
263     else
264         apefrm_remove(ape_mem,APE_TAG_FIELD_ALBUM);
265 
266     /******************************
267      * Disc Number and Disc Total *
268      ******************************/
269     if (!et_str_empty (FileTag->disc_number))
270     {
271         if (!et_str_empty (FileTag->disc_total))
272         {
273             string = g_strconcat (FileTag->disc_number, "/",
274                                   FileTag->disc_total, NULL);
275         }
276         else
277         {
278             string = g_strconcat (FileTag->disc_number, NULL);
279         }
280 
281         apefrm_add (ape_mem, 0, APE_TAG_FIELD_PART, string);
282         g_free (string);
283     }
284     else
285     {
286         apefrm_remove (ape_mem, APE_TAG_FIELD_PART);
287     }
288 
289     /********
290      * Year *
291      ********/
292     if (!et_str_empty (FileTag->year))
293         apefrm_add(ape_mem, 0, APE_TAG_FIELD_YEAR, FileTag->year);
294     else
295         apefrm_remove(ape_mem,APE_TAG_FIELD_YEAR);
296 
297     /*************************
298      * Track and Total Track *
299      *************************/
300     if (!et_str_empty (FileTag->track))
301     {
302         if (!et_str_empty (FileTag->track_total))
303             string = g_strconcat(FileTag->track,"/",FileTag->track_total,NULL);
304         else
305             string = g_strconcat(FileTag->track,NULL);
306         apefrm_add(ape_mem, 0, APE_TAG_FIELD_TRACK, string);
307         g_free(string);
308     } else
309         apefrm_remove(ape_mem,APE_TAG_FIELD_TRACK);
310 
311     /*********
312      * Genre *
313      *********/
314     if (!et_str_empty (FileTag->genre))
315         apefrm_add(ape_mem, 0, APE_TAG_FIELD_GENRE, FileTag->genre);
316     else
317         apefrm_remove(ape_mem,APE_TAG_FIELD_GENRE);
318 
319     /***********
320      * Comment *
321      ***********/
322     if (!et_str_empty (FileTag->comment))
323         apefrm_add (ape_mem, 0, APE_TAG_FIELD_COMMENT, FileTag->comment);
324     else
325         apefrm_remove(ape_mem,APE_TAG_FIELD_COMMENT);
326 
327     /************
328      * Composer *
329      ************/
330     if (!et_str_empty (FileTag->composer))
331         apefrm_add(ape_mem, 0, APE_TAG_FIELD_COMPOSER, FileTag->composer);
332     else
333         apefrm_remove(ape_mem,APE_TAG_FIELD_COMPOSER);
334 
335     /*******************
336      * Original artist *
337      *******************/
338     if (!et_str_empty (FileTag->orig_artist))
339         apefrm_add(ape_mem, 0, "Original Artist", FileTag->orig_artist);
340     else
341         apefrm_remove(ape_mem,"Original Artist");
342 
343     /*************
344      * Copyright *
345      *************/
346     if (!et_str_empty (FileTag->copyright))
347         apefrm_add(ape_mem, 0, APE_TAG_FIELD_COPYRIGHT, FileTag->copyright);
348     else
349         apefrm_remove(ape_mem,APE_TAG_FIELD_COPYRIGHT);
350 
351     /*******
352      * URL *
353      *******/
354     if (!et_str_empty (FileTag->url))
355         apefrm_add(ape_mem, 0, APE_TAG_FIELD_RELATED_URL, FileTag->url);
356     else
357         apefrm_remove(ape_mem,APE_TAG_FIELD_RELATED_URL);
358 
359     /**************
360      * Encoded by *
361      **************/
362     if (!et_str_empty (FileTag->encoded_by))
363         apefrm_add(ape_mem, 0, "Encoded By", FileTag->encoded_by);
364     else
365         apefrm_remove(ape_mem,"Encoded By");
366 
367     /* reread all tag-type again  excl. changed frames by apefrm_remove() */
368     if (apetag_save (filename_in, ape_mem, APE_TAG_V2 + SAVE_NEW_OLD_APE_TAG)
369         != 0)
370     {
371         g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "%s",
372                      _("Failed to write APE tag"));
373         apetag_free (ape_mem);
374         return FALSE;
375     }
376 
377     apetag_free(ape_mem);
378 
379     return TRUE;
380 }
381