1 /* EasyTAG - Tag editor for audio files
2  * Copyright (C) 2014-2016  David King <amigadave@amigadave.com>
3  * Copyright (C) 2001-2003  Jerome Couderc <easytag@gmail.com>
4  * Copyright (C) 2006-2007  Alexey Illarionov <littlesavage@rambler.ru>
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 <errno.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/fcntl.h>
31 
32 #include "id3_tag.h"
33 #include "picture.h"
34 #include "browser.h"
35 #include "setting.h"
36 #include "misc.h"
37 #include "et_core.h"
38 #include "charset.h"
39 
40 #include "win32/win32dep.h"
41 
42 
43 #ifdef ENABLE_MP3
44 
45 #include <id3tag.h>
46 #include "genres.h"
47 
48 
49 /****************
50  * Declarations *
51  ****************/
52 #define MULTIFIELD_SEPARATOR " - "
53 #define EASYTAG_STRING_ENCODEDBY "Encoded by"
54 
55 enum {
56     EASYTAG_ID3_FIELD_LATIN1        = 0x0001,
57     EASYTAG_ID3_FIELD_LATIN1FULL    = 0x0002,
58     EASYTAG_ID3_FIELD_LATIN1LIST    = 0x0004,
59     EASYTAG_ID3_FIELD_STRING        = 0x0008,
60     EASYTAG_ID3_FIELD_STRINGFULL    = 0x0010,
61     EASYTAG_ID3_FIELD_STRINGLIST    = 0x0020,
62     EASYTAG_ID3_FIELD_LANGUAGE      = 0x0040
63 };
64 
65 /**************
66  * Prototypes *
67  **************/
68 static int    etag_guess_byteorder      (const id3_ucs4_t *ustr, gchar **ret);
69 static int    etag_ucs42gchar           (const id3_ucs4_t *usrc, unsigned is_latin, unsigned is_utf16, gchar **res);
70 static int    libid3tag_Get_Frame_Str   (const struct id3_frame *frame, unsigned etag_field_type, gchar **retstr);
71 
72 static void   Id3tag_delete_frames      (struct id3_tag *tag, const gchar *name, int start);
73 static void   Id3tag_delete_txxframes   (struct id3_tag *tag, const gchar *param1, int start);
74 static struct id3_frame *Id3tag_find_and_create_frame    (struct id3_tag *tag, const gchar *name);
75 static int    id3taglib_set_field       (struct id3_frame *frame, const gchar *str, enum id3_field_type type, int num, int clear, int id3v1);
76 static int    etag_set_tags             (const gchar *str, const char *frame_name, enum id3_field_type field_type, struct id3_tag *v1tag, struct id3_tag *v2tag, gboolean *strip_tags);
77 static gboolean etag_write_tags (const gchar *filename, struct id3_tag const *v1tag,
78                             struct id3_tag const *v2tag, gboolean strip_tags, GError **error);
79 
80 /*************
81  * Functions *
82  *************/
83 
84 /*
85  * Read id3v1.x / id3v2 tag and load data into the File_Tag structure.
86  * Returns TRUE on success, else FALSE.
87  * If a tag entry exists (ex: title), we allocate memory, else value stays to NULL
88  */
89 gboolean
id3tag_read_file_tag(GFile * gfile,File_Tag * FileTag,GError ** error)90 id3tag_read_file_tag (GFile *gfile,
91                       File_Tag *FileTag,
92                       GError **error)
93 {
94     GInputStream *istream;
95     gsize bytes_read;
96     GSeekable *seekable;
97     gchar *filename;
98     int fd;
99     struct id3_file *file;
100     struct id3_tag *tag;
101     struct id3_frame *frame;
102     union id3_field *field;
103     gchar *string1, *string2;
104     EtPicture *prev_pic = NULL;
105     int i, j;
106     unsigned tmpupdate, update = 0;
107     long tagsize;
108 
109     g_return_val_if_fail (gfile != NULL && FileTag != NULL, FALSE);
110     g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
111 
112     istream = G_INPUT_STREAM (g_file_read (gfile, NULL, error));
113 
114     if (!istream)
115     {
116         return FALSE;
117     }
118 
119     string1 = g_malloc0 (ID3_TAG_QUERYSIZE);
120 
121     /* Check if the file has an ID3v2 tag or/and an ID3v1 tags.
122      * 1) ID3v2 tag. */
123     if (!g_input_stream_read_all (istream, string1, ID3_TAG_QUERYSIZE,
124                                   &bytes_read, NULL, error))
125     {
126         g_object_unref (istream);
127         g_free (string1);
128         return FALSE;
129     }
130     else if (bytes_read != ID3_TAG_QUERYSIZE)
131     {
132         g_object_unref (istream);
133         g_free (string1);
134         g_set_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT, "%s",
135                      _("Error reading tags from file"));
136         return FALSE;
137     }
138 
139     if ((tagsize = id3_tag_query((id3_byte_t const *)string1, ID3_TAG_QUERYSIZE)) <= ID3_TAG_QUERYSIZE)
140     {
141         /* ID3v2 tag not found! */
142         update = g_settings_get_boolean (MainSettings, "id3v2-enabled");
143     }else
144     {
145         /* ID3v2 tag found */
146         if (!g_settings_get_boolean (MainSettings, "id3v2-enabled"))
147         {
148             /* To delete the tag. */
149             update = 1;
150         }else
151         {
152             /* Determine version if user want to upgrade old tags */
153             if (g_settings_get_boolean (MainSettings, "id3v2-convert-old")
154             && (string1 = g_realloc (string1, tagsize))
155                 && g_input_stream_read_all (istream,
156                                             &string1[ID3_TAG_QUERYSIZE],
157                                             tagsize - ID3_TAG_QUERYSIZE,
158                                             &bytes_read, NULL, error)
159                 && bytes_read == (gsize)(tagsize - ID3_TAG_QUERYSIZE)
160             && (tag = id3_tag_parse((id3_byte_t const *)string1, tagsize))
161                )
162             {
163                 unsigned version = id3_tag_version(tag);
164 #ifdef ENABLE_ID3LIB
165                 /* Besides upgrade old tags we will downgrade id3v2.4 to id3v2.3 */
166                 if (g_settings_get_boolean (MainSettings, "id3v2-version-4"))
167                 {
168                     update = (ID3_TAG_VERSION_MAJOR(version) < 4);
169                 }else
170                 {
171                     update = ((ID3_TAG_VERSION_MAJOR(version) < 3)
172                             | (ID3_TAG_VERSION_MAJOR(version) == 4));
173                 }
174 #else
175                 update = (ID3_TAG_VERSION_MAJOR(version) < 4);
176 #endif
177                 id3_tag_delete(tag);
178             }
179         }
180     }
181 
182     /* 2) ID3v1 tag. */
183     seekable = G_SEEKABLE (istream);
184 
185     if (!g_seekable_can_seek (seekable))
186     {
187         g_object_unref (istream);
188         g_free (string1);
189         g_set_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT, "%s",
190                      _("Error reading tags from file"));
191         return FALSE;
192     }
193 
194     /* Go to the beginning of ID3v1 tag. */
195     if (g_seekable_seek (seekable, -ID3V1_TAG_SIZE, G_SEEK_END, NULL, error)
196     && (string1)
197         && g_input_stream_read_all (istream, string1, 3, &bytes_read, NULL,
198                                     NULL /* Ignore errors. */)
199         && bytes_read == 3
200     && (string1[0] == 'T')
201     && (string1[1] == 'A')
202     && (string1[2] == 'G')
203        )
204     {
205         /* ID3v1 tag found! */
206         if (!g_settings_get_boolean (MainSettings, "id3v1-enabled"))
207         {
208             update = 1;
209         }
210     }else
211     {
212         /* ID3v1 tag not found! */
213         if (g_settings_get_boolean (MainSettings, "id3v1-enabled"))
214         {
215             update = 1;
216         }
217     }
218 
219     g_free (string1);
220     g_object_unref (istream);
221 
222     filename = g_file_get_path (gfile);
223 
224     if ((fd = g_open (filename, O_RDONLY, 0)) == -1)
225     {
226         g_free (filename);
227         g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
228                      _("Error reading tags from file"));
229         return FALSE;
230     }
231 
232     g_free (filename);
233 
234     /* The fd ownership is transferred to id3tag. */
235     if ((file = id3_file_fdopen (fd, ID3_FILE_MODE_READONLY)) == NULL)
236     {
237         g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
238                      _("Error reading tags from file"));
239         return FALSE;
240     }
241 
242     if ( ((tag = id3_file_tag(file)) == NULL)
243     ||   (tag->nframes == 0))
244     {
245         id3_file_close(file);
246         g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
247                      _("Error reading tags from file"));
248         return FALSE;
249     }
250 
251 
252     /****************
253      * Title (TIT2) *
254      ****************/
255     if ( (frame = id3_tag_findframe(tag, ID3_FRAME_TITLE, 0)) )
256         update |= libid3tag_Get_Frame_Str(frame, EASYTAG_ID3_FIELD_STRINGLIST, &FileTag->title);
257 
258     /*****************
259      * Artist (TPE1) *
260      *****************/
261     if ( (frame = id3_tag_findframe(tag, ID3_FRAME_ARTIST, 0)) )
262         update |= libid3tag_Get_Frame_Str(frame, EASYTAG_ID3_FIELD_STRINGLIST, &FileTag->artist);
263 
264     /*****************
265      * Album Artist (TPE2) *
266      *****************/
267     if ( (frame = id3_tag_findframe(tag, "TPE2", 0)) )
268         update |= libid3tag_Get_Frame_Str(frame, EASYTAG_ID3_FIELD_STRINGLIST, &FileTag->album_artist);
269 
270     /****************
271      * Album (TALB) *
272      ****************/
273     if ( (frame = id3_tag_findframe(tag, ID3_FRAME_ALBUM, 0)) )
274         update |= libid3tag_Get_Frame_Str(frame, ~0, &FileTag->album);
275 
276     /************************
277      * Part of a set (TPOS) *
278      ************************/
279     if ((frame = id3_tag_findframe (tag, "TPOS", 0)))
280     {
281         update |= libid3tag_Get_Frame_Str (frame, ~0, &string1);
282 
283         if (string1)
284         {
285             string2 = strchr (string1, '/');
286 
287             if (string2)
288             {
289                 FileTag->disc_total = et_disc_number_to_string (atoi (string2
290                                                                       + 1));
291                 *string2 = '\0';
292             }
293 
294             FileTag->disc_number = et_disc_number_to_string (atoi (string1));
295             g_free (string1);
296         }
297     }
298 
299     /********************
300      * Year (TYER/TDRC) *
301      ********************/
302     if ( (frame = id3_tag_findframe(tag, ID3_FRAME_YEAR, 0)) )
303     {
304         update |= libid3tag_Get_Frame_Str(frame, ~0, &string1);
305         if ( string1 )
306         {
307             g_strstrip (string1);
308             FileTag->year = string1;
309         }
310     }
311 
312     /********************************
313      * Track and Total Track (TRCK) *
314      ********************************/
315     if ( (frame = id3_tag_findframe(tag, ID3_FRAME_TRACK, 0)) )
316     {
317         update |= libid3tag_Get_Frame_Str(frame, ~0, &string1);
318         if ( string1 )
319         {
320             string2 = strchr (string1, '/');
321 
322             if (string2)
323             {
324                 FileTag->track_total = et_track_number_to_string (atoi (string2 + 1));
325                 *string2 = '\0'; // To cut string1
326             }
327             FileTag->track = et_track_number_to_string (atoi (string1));
328 
329             g_free(string1);
330 
331         }
332     }
333 
334     /****************
335      * Genre (TCON) *
336      ****************/
337     if ( (frame = id3_tag_findframe(tag, ID3_FRAME_GENRE, 0)) )
338     {
339         update |= libid3tag_Get_Frame_Str(frame, ~0, &string1);
340         if ( string1 )
341         {
342             /*
343              * We manipulate only the name of the genre
344              * Genre is written like this :
345              *    - "(<genre_id>)"              -> "(3)"
346              *    - "<genre_name>"              -> "Dance"
347              *    - "(<genre_id>)<refinement>"  -> "(3)EuroDance"
348              */
349             gchar *tmp;
350             unsigned genre = 0;
351             FileTag->genre = NULL;
352 
353             if ((string1[0] == '(') && g_ascii_isdigit (string1[1])
354                 && (tmp = strchr (string1 + 1, ')')) && *(tmp+1))
355                 /* Convert a genre written as '(3)EuroDance' into 'EuroDance' */
356             {
357                 FileTag->genre = g_strdup (tmp + 1);
358             }
359             else if ((string1[0] == '(') && g_ascii_isdigit (string1[1])
360                      && strchr (string1, ')'))
361             {
362                 /* Convert a genre written as '(3)' into 'Dance' */
363                 genre = strtol (string1 +1 , &tmp, 10);
364                 if (*tmp != ')')
365                 {
366                     FileTag->genre = g_strdup (string1);
367                 }
368             }
369             else
370             {
371                 genre = strtol (string1, &tmp, 10);
372                 if (tmp == string1)
373                 {
374                     FileTag->genre = g_strdup (string1);
375                 }
376             }
377 
378             if (!FileTag->genre)
379             {
380                 if (id3_genre_index (genre))
381                 {
382                     FileTag->genre = (gchar *)id3_ucs4_utf8duplicate (id3_genre_index (genre));
383                 }
384                 else if (strcmp (genre_no (genre),
385                                  genre_no (ID3_INVALID_GENRE)) != 0)
386                 {
387                     /* If the integer genre is not found in the (outdated)
388                      * libid3tag index, try the EasyTAG index instead. */
389                     FileTag->genre = g_strdup (genre_no (genre));
390                 }
391             }
392 
393             g_free(string1);
394         }
395     }
396 
397     /******************
398      * Comment (COMM) *
399      ******************/
400     if ( (frame = id3_tag_findframe(tag, ID3_FRAME_COMMENT, 0)) )
401     {
402         update |= libid3tag_Get_Frame_Str(frame, /* EASYTAG_ID3_FIELD_STRING | */ EASYTAG_ID3_FIELD_STRINGFULL,
403             &FileTag->comment);
404         /*{
405             gchar *comment1 = Id3tag_Get_Field(frame,ID3FN_DESCRIPTION)
406             gchar *comment2 = Id3tag_Get_Field(id3_frame,ID3FN_LANGUAGE)
407         }*/
408     }
409 
410     /*******************
411      * Composer (TCOM) *
412      *******************/
413     if ( (frame = id3_tag_findframe(tag, "TCOM", 0)) )
414         update |= libid3tag_Get_Frame_Str(frame, ~0, &FileTag->composer);
415 
416     /**************************
417      * Original artist (TOPE) *
418      **************************/
419     if ( (frame = id3_tag_findframe(tag, "TOPE", 0)) )
420         update |= libid3tag_Get_Frame_Str(frame, ~0, &FileTag->orig_artist);
421 
422     /*******************
423      * Copyright (TCOP)*
424      *******************/
425     if ( (frame = id3_tag_findframe(tag, "TCOP", 0)) )
426         update |= libid3tag_Get_Frame_Str(frame, ~0, &FileTag->copyright);
427 
428     /**************
429      * URL (WXXX) *
430      **************/
431     if ( (frame = id3_tag_findframe(tag, "WXXX", 0)) )
432         update |= libid3tag_Get_Frame_Str(frame, EASYTAG_ID3_FIELD_LATIN1, &FileTag->url);
433 
434     /*******************************
435      * Encoded by (TENC) or (TXXX) *
436      *******************************/
437     if ( (frame = id3_tag_findframe(tag, "TENC", 0)) )
438         update |= libid3tag_Get_Frame_Str(frame, ~0, &FileTag->encoded_by);
439 
440     /* Encoded by in TXXX frames */
441     string1 = NULL;
442     for (i = 0; (frame = id3_tag_findframe(tag, "TXX", i)); i++)
443     {
444         // Do nothing if already read...
445         if (FileTag->encoded_by)
446             break;
447 
448         tmpupdate = libid3tag_Get_Frame_Str(frame, ~0, &string1);
449         if (string1)
450         {
451             if (strncmp (string1,
452                          EASYTAG_STRING_ENCODEDBY MULTIFIELD_SEPARATOR,
453                          strlen (EASYTAG_STRING_ENCODEDBY MULTIFIELD_SEPARATOR)) == 0)
454             {
455                 FileTag->encoded_by = g_strdup(&string1[sizeof(EASYTAG_STRING_ENCODEDBY) + sizeof(MULTIFIELD_SEPARATOR) - 2]);
456                 g_free(string1);
457                 update |= tmpupdate;
458             }else
459                 g_free(string1);
460         }
461     }
462 
463     /******************
464      * Picture (APIC) *
465      ******************/
466     for (i = 0; (frame = id3_tag_findframe(tag, "APIC", i)); i++)
467     {
468         GBytes *bytes = NULL;
469         EtPictureType type = ET_PICTURE_TYPE_FRONT_COVER;
470         gchar *description;
471         EtPicture *pic;
472 
473         /* Picture file data. */
474         for (j = 0; (field = id3_frame_field(frame, j)); j++)
475         {
476             enum id3_field_type field_type;
477 
478             field_type = id3_field_type (field);
479 
480             if (field_type == ID3_FIELD_TYPE_BINARYDATA)
481             {
482                 id3_length_t size;
483                 id3_byte_t const *data;
484 
485                 data = id3_field_getbinarydata (field, &size);
486 
487                 if (data)
488                 {
489                     if (bytes)
490                     {
491                         g_bytes_unref (bytes);
492                     }
493 
494                     bytes = g_bytes_new (data, size);
495                 }
496             }
497             else if (field_type == ID3_FIELD_TYPE_INT8)
498             {
499                 type = id3_field_getint (field);
500             }
501         }
502 
503         /* Picture description. The accepted fields are restricted to those
504          * of string type, as the description field is the only one of string
505          * type in the APIC tag (the MIME type is Latin1 type). */
506         update |= libid3tag_Get_Frame_Str (frame, EASYTAG_ID3_FIELD_STRING,
507                                            &description);
508 
509         pic = et_picture_new (type, description ? description : "", 0, 0,
510                               bytes);
511         g_bytes_unref (bytes);
512         g_free (description);
513 
514         if (!prev_pic)
515         {
516             FileTag->picture = pic;
517         }
518         else
519         {
520             prev_pic->next = pic;
521         }
522 
523         prev_pic = pic;
524     }
525 
526     /**********************
527      * Lyrics (SYLC/USLT) *
528      **********************/
529     /** see also id3/misc_support.h  **
530     if ( (id3_frame = ID3Tag_FindFrameWithID(id3_tag,ID3FID_SYNCEDLYRICS)) )
531     {
532         gulong  size = 0;
533         guchar *data = NULL;
534         gchar  *description = NULL;
535         gchar  *language = NULL;
536         gint timestamp_format = 0;
537         gint sync_type = 0;
538 
539         // SyncLyrics data
540         if ( (id3_field = ID3Frame_GetField(id3_frame, ID3FN_DATA)) )
541         {
542             size = ID3Field_Size(id3_field);
543             data = g_malloc(size);
544             ID3Field_GetBINARY(id3_field, data, size);
545         }
546 
547         // SyncLyrics description
548         description = Id3tag_Get_Field(id3_frame, ID3FN_DESCRIPTION);
549 
550         // SyncLyrics language
551         language = Id3tag_Get_Field(id3_frame, ID3FN_LANGUAGE);
552 
553         // SyncLyrics timestamp field
554         if ( (id3_field = ID3Frame_GetField(id3_frame, ID3FN_TIMESTAMPFORMAT)) )
555         {
556             timestamp_format = ID3Field_GetINT(id3_field);
557         }
558 
559         // SyncLyrics content type
560         if ( (id3_field = ID3Frame_GetField(id3_frame, ID3FN_CONTENTTYPE)) )
561         {
562             sync_type = ID3Field_GetINT(id3_field);
563         }
564 
565         // Print data
566         // j.a. Pouwelse - pouwelse :
567         //      http://sourceforge.net/tracker/index.php?func=detail&aid=401873&group_id=979&atid=300979
568         {
569             char tag[255];
570             unsigned int time;
571             luint pos = 0;
572 
573             g_print("SyncLyrics/description      : %s\n",description);
574             g_print("SyncLyrics/language         : %s\n",language);
575             g_print("SyncLyrics/timestamp format : %s (%d)\n",timestamp_format==ID3TSF_FRAME ? "ID3TSF_FRAME" : timestamp_format==ID3TSF_MS ? "ID3TSF_MS" : "" ,timestamp_format);
576             g_print("SyncLyrics/sync type        : %s (%d)\n",sync_type==ID3CT_LYRICS ? "ID3CT_LYRICS" : "",sync_type);
577 
578 
579             g_print("SyncLyrics size             : %d\n", size);
580             g_print("Lyrics/data :\n");
581             while (pos < size)
582             {
583                 strcpy(tag,data+pos);
584                 //g_print("txt start=%d ",pos);
585                 pos+=strlen(tag)+1;             // shift string and terminating \0
586                 //g_print("txt end=%d ",pos);
587                 memcpy(&time,data+pos,4);
588                 pos+=4;
589                 //g_print("%d -> %s\n",time,tag);
590                 g_print("%s",tag);
591             }
592         }
593 
594     } **/
595 
596     if (update)
597         FileTag->saved = FALSE;
598 
599     /* Free allocated data */
600     id3_file_close(file);
601 
602     return TRUE;
603 }
604 
605 
606 /* Guess byteorder of UTF-16 string that was converted to 'ustr' (some ID3
607  * tags contain UTF-16 string without BOM and in fact can be UTF16BE and
608  * UTF-16LE). Function correct byteorder, if it is needed, and return new
609  * corrected utf-8 string in 'ret'.
610  * Return value of function is 0 if byteorder was not changed
611  */
612 static int
etag_guess_byteorder(const id3_ucs4_t * ustr,gchar ** ret)613 etag_guess_byteorder(const id3_ucs4_t *ustr, gchar **ret) /* XXX */
614 {
615     unsigned i, len;
616     gunichar *gstr;
617     gchar *tmp, *str, *str2;
618     gchar *charset;
619 
620     if (!ustr || !*ustr)
621     {
622         if (ret)
623             *ret = NULL;
624         return 0;
625     }
626 
627     if (g_settings_get_boolean (MainSettings, "id3-override-read-encoding"))
628     {
629         charset = g_settings_get_string (MainSettings,
630                                          "id3v1v2-charset");
631     }
632     else if (!g_settings_get_boolean (MainSettings, "id3v2-enable-unicode"))
633     {
634         charset = g_settings_get_string (MainSettings,
635                                          "id3v2-no-unicode-charset"); /* XXX */
636     }
637     else
638     {
639         const gchar *temp;
640         g_get_charset (&temp);
641         charset = g_strdup (temp);
642     }
643 
644     if (!charset)
645     {
646         charset = g_strdup ("ISO-8859-1");
647     }
648 
649     tmp = (gchar *)id3_ucs4_utf8duplicate(ustr);
650     str = g_convert(tmp, -1, charset, "UTF-8", NULL, NULL, NULL);
651     if (str)
652     {
653         g_free(str);
654         if (ret)
655             *ret = tmp;
656         else
657             free (tmp);
658         g_free (charset);
659         return 0; /* byteorder not changed */
660     }
661 
662     for (len = 0; ustr[len]; len++);
663 
664     gstr = g_try_malloc(sizeof(gunichar) * (len + 1));
665     if ( gstr == NULL )
666     {
667         if (ret)
668             *ret = tmp;
669         else
670             free(tmp);
671         g_free (charset);
672         return 0;
673     }
674 
675     for (i = 0; i <= len; i++)
676         gstr[i] = ((ustr[i] & 0xff00) >> 8) | ((ustr[i] & 0xff) << 8);
677     str = g_ucs4_to_utf8(gstr, len, NULL, NULL, NULL);
678     g_free(gstr);
679 
680     if (str == NULL)
681     {
682         if (ret)
683             *ret = tmp;
684         else
685             free(tmp);
686         g_free (charset);
687         return 0;
688     }
689 
690     str2 = g_convert(str, -1, charset, "UTF-8", NULL, NULL, NULL);
691 
692     if (str2 && *str2)
693     {
694         g_free(str2);
695         free(tmp);
696         if (ret)
697             *ret = str;
698         else
699             free(str);
700         g_free (charset);
701         return 1;
702     }
703 
704     g_free(str);
705 
706     if (ret)
707         *ret = tmp;
708     else
709         free(tmp);
710 
711     g_free (charset);
712     return 0;
713 }
714 
715 
716 /* convert ucs4 string to utf-8 gchar in 'res' according to easytag charset
717  * conversion settings and field type.
718  * function return 0 if byteorder of utf-16 string was changed
719  */
720 static int
etag_ucs42gchar(const id3_ucs4_t * usrc,unsigned is_latin,unsigned is_utf16,gchar ** res)721 etag_ucs42gchar(const id3_ucs4_t *usrc, unsigned is_latin,
722                 unsigned is_utf16, gchar **res)
723 {
724     gchar *latinstr, *retstr;
725     int retval;
726 
727     if (!usrc || !*usrc)
728     {
729         if (res)
730             *res = NULL;
731         return 0;
732     }
733 
734     retval = 0, retstr = NULL;
735 
736     if (is_latin && g_settings_get_boolean (MainSettings,
737                                             "id3-override-read-encoding"))
738     {
739         if ((latinstr = (gchar *)id3_ucs4_latin1duplicate(usrc)))
740         {
741             gint id3v1v2_charset;
742             const gchar * charset;
743 
744             id3v1v2_charset = g_settings_get_enum (MainSettings,
745                                                    "id3v1v2-charset");
746             charset = et_charset_get_name_from_index (id3v1v2_charset);
747             retstr = convert_string (latinstr, charset, "UTF-8", FALSE);
748             free(latinstr);
749         }
750     }else
751     {
752         if (is_utf16)
753         {
754             retval |= etag_guess_byteorder(usrc, &retstr);
755         }else
756         {
757             retstr = (gchar *)id3_ucs4_utf8duplicate(usrc);
758         }
759     }
760 
761     if (res)
762         *res = retstr;
763     else
764         free (retstr);
765 
766     return retval;
767 }
768 
769 
770 static int
libid3tag_Get_Frame_Str(const struct id3_frame * frame,unsigned etag_field_type,gchar ** retstr)771 libid3tag_Get_Frame_Str (const struct id3_frame *frame,
772                          unsigned etag_field_type,
773                          gchar **retstr)
774 {
775     const union id3_field *field;
776     unsigned i;
777     gchar *ret;
778     unsigned is_latin, is_utf16;
779     unsigned retval;
780 
781     ret = NULL;
782     retval = 0;
783     is_latin = 1, is_utf16 = 0;
784 
785     /* Find the encoding used for the field. */
786     for (i = 0; (field = id3_frame_field (frame, i)); i++)
787     {
788         if (id3_field_type(field) == ID3_FIELD_TYPE_TEXTENCODING)
789         {
790             is_latin = (id3_field_gettextencoding(field) == ID3_FIELD_TEXTENCODING_ISO_8859_1);
791             is_utf16 = (id3_field_gettextencoding(field) == ID3_FIELD_TEXTENCODING_UTF_16);
792             break;
793         }
794     }
795 
796     for (i = 0; (field = id3_frame_field (frame, i)); i++)
797     {
798         unsigned field_type;
799         gchar *tmpstr = NULL;
800 
801         switch (field_type = id3_field_type(field))
802         {
803             case ID3_FIELD_TYPE_LATIN1:
804             case ID3_FIELD_TYPE_LATIN1FULL:
805             {
806                 gchar *latinstr;
807 
808                 if (field_type == ID3_FIELD_TYPE_LATIN1)
809                 {
810                     if (!(etag_field_type & EASYTAG_ID3_FIELD_LATIN1))
811                         continue;
812                 }
813                 else
814                 {
815                     if (!(etag_field_type & EASYTAG_ID3_FIELD_LATIN1FULL))
816                         continue;
817                 }
818 
819                 latinstr = g_strdup (field_type == ID3_FIELD_TYPE_LATIN1 ? (const gchar *)id3_field_getlatin1 (field)
820                                                                          : (const gchar *)id3_field_getfulllatin1 (field));
821 
822                 if (g_settings_get_boolean (MainSettings,
823                                             "id3-override-read-encoding"))
824                 {
825                     gint id3v1v2_charset;
826                     const gchar * charset;
827 
828                     id3v1v2_charset = g_settings_get_enum (MainSettings,
829                                                            "id3v1v2-charset");
830                     charset = et_charset_get_name_from_index (id3v1v2_charset);
831                     tmpstr = convert_string (latinstr, charset, "UTF-8", FALSE);
832                     g_free (latinstr);
833                 }
834                 else
835                 {
836                     tmpstr = latinstr;
837                 }
838 
839                 break;
840             }
841 
842             case ID3_FIELD_TYPE_STRING:
843             case ID3_FIELD_TYPE_STRINGFULL:
844             {
845                 const id3_ucs4_t *usrc;
846 
847                 if (field_type == ID3_FIELD_TYPE_STRING)
848                 {
849                     if (!(etag_field_type & EASYTAG_ID3_FIELD_STRING))
850                         continue;
851                 }
852                 else
853                 {
854                     if (!(etag_field_type & EASYTAG_ID3_FIELD_STRINGFULL))
855                         continue;
856                 }
857 
858                 usrc = (field_type == ID3_FIELD_TYPE_STRING) ? id3_field_getstring (field)
859                                                              : id3_field_getfullstring (field);
860                 retval |= etag_ucs42gchar (usrc, is_latin, is_utf16, &tmpstr);
861                 break;
862             }
863 
864             case ID3_FIELD_TYPE_STRINGLIST:
865             {
866                 unsigned strcnt, j;
867 
868                 if (!(etag_field_type & EASYTAG_ID3_FIELD_STRINGLIST))
869                     continue;
870 
871                 strcnt = id3_field_getnstrings (field);
872 
873                 for (j = 0; j < strcnt; j++)
874                 {
875                     gchar *tmpstr2 = NULL;
876 
877                     retval |= etag_ucs42gchar (id3_field_getstrings (field, j),
878                                                is_latin, is_utf16, &tmpstr2);
879 
880                     if (tmpstr2 && *tmpstr2 && g_utf8_validate(tmpstr2, -1, NULL))
881                     {
882                         if (tmpstr)
883                         {
884                             gchar *to_free = tmpstr;
885                             tmpstr = g_strconcat (tmpstr, " ", tmpstr2, NULL);
886 
887                             g_free (to_free);
888                         }
889                         else
890                         {
891                             tmpstr = g_strdup (tmpstr2);
892                         }
893                     }
894 
895                     free (tmpstr2);
896                 }
897 
898                 break;
899             }
900 
901             default:
902                 break;
903         }
904 
905         if (tmpstr && *tmpstr && g_utf8_validate (tmpstr, -1, NULL))
906         {
907             if (ret)
908             {
909                 gchar *to_free = ret;
910                 ret = g_strconcat (ret, MULTIFIELD_SEPARATOR, tmpstr, NULL);
911                 g_free (to_free);
912             }
913             else
914             {
915                 ret = g_strdup (tmpstr);
916             }
917         }
918 
919         g_free (tmpstr);
920     }
921 
922     if (retstr)
923     {
924         *retstr = ret;
925     }
926     else
927     {
928         g_free (ret);
929     }
930 
931     return retval;
932 }
933 
934 
935 /*
936  * Write the ID3 tags to the file. Returns TRUE on success, else 0.
937  */
938 gboolean
id3tag_write_file_v24tag(const ET_File * ETFile,GError ** error)939 id3tag_write_file_v24tag (const ET_File *ETFile,
940                           GError **error)
941 {
942     const File_Tag *FileTag;
943     const gchar *filename;
944     struct id3_tag   *v1tag, *v2tag;
945     struct id3_frame *frame;
946     union id3_field  *field;
947     gchar            *string1;
948     EtPicture          *pic;
949     gboolean strip_tags = TRUE;
950     guchar genre_value = ID3_INVALID_GENRE;
951     gboolean success;
952 
953     g_return_val_if_fail (ETFile != NULL && ETFile->FileTag != NULL, FALSE);
954     g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
955 
956     FileTag       = (File_Tag *)ETFile->FileTag->data;
957     filename      = ((File_Name *)ETFile->FileNameCur->data)->value;
958 
959     v1tag = v2tag = NULL;
960 
961     /* Write ID3v2 tag. */
962     if (g_settings_get_boolean (MainSettings, "id3v2-enabled"))
963     {
964         int fd;
965         struct id3_file *file;
966         struct id3_tag *tmptag;
967         unsigned tagsize;
968         id3_byte_t *tmpbuf = NULL;
969 
970         if ((fd = g_open (filename, O_RDONLY, 0)) == -1)
971         {
972             g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
973                          _("Error reading tags from file"));
974             return FALSE;
975         }
976 
977         /* Read old v2 tag */
978         if ((file = id3_file_fdopen (fd, ID3_FILE_MODE_READONLY)) == NULL)
979         {
980             g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
981                          _("Error reading tags from file"));
982             return FALSE;
983         }
984 
985         if ((tmptag = id3_file_tag(file)) == NULL)
986         {
987             g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
988                          _("Error reading tags from file"));
989             id3_file_close(file);
990             return FALSE;
991         }
992 
993         id3_tag_options(tmptag, ID3_TAG_OPTION_UNSYNCHRONISATION
994                               | ID3_TAG_OPTION_ID3V1
995                               | ID3_TAG_OPTION_COMPRESSION
996                               | ID3_TAG_OPTION_APPENDEDTAG,
997                         //ID3_TAG_OPTION_UNSYNCHRONISATION); // Taglib doesn't support frames with unsynchronisation (patch from Alexey Illarionov) http://bugs.kde.org/show_bug.cgi?id=138829
998                         0);
999 
1000         /* XXX Create new tag and copy all frames*/
1001         tagsize = id3_tag_render(tmptag, NULL);
1002         if ((tagsize > 10)
1003         && (tmpbuf = g_try_malloc(tagsize))
1004         && (id3_tag_render(tmptag, tmpbuf) != 0)
1005         )
1006             v2tag = id3_tag_parse(tmpbuf, tagsize);
1007         g_free(tmpbuf);
1008 
1009         if (v2tag == NULL)
1010         {
1011             if ((v2tag = id3_tag_new()) == NULL)
1012             {
1013                 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
1014                              _("Error reading tags from file"));
1015                 id3_file_close(file);
1016                 return FALSE;
1017             }
1018         }
1019 
1020         id3_file_close(file);
1021 
1022         /* Set padding  XXX */
1023         if ((v2tag->paddedsize < 1024)
1024         || ((v2tag->paddedsize > 4096) && (tagsize < 1024))
1025         )
1026             v2tag->paddedsize = 1024;
1027 
1028         /* Set options */
1029         id3_tag_options(v2tag, ID3_TAG_OPTION_UNSYNCHRONISATION
1030                              | ID3_TAG_OPTION_APPENDEDTAG
1031                              | ID3_TAG_OPTION_ID3V1
1032                              | ID3_TAG_OPTION_CRC
1033                              | ID3_TAG_OPTION_COMPRESSION,
1034                         //ID3_TAG_OPTION_UNSYNCHRONISATION); // Taglib doesn't support frames with unsynchronisation (patch from Alexey Illarionov) http://bugs.kde.org/show_bug.cgi?id=138829
1035                         0);
1036 
1037         if (g_settings_get_boolean (MainSettings, "id3v2-crc32"))
1038         {
1039             id3_tag_options (v2tag, ID3_TAG_OPTION_CRC, ~0);
1040         }
1041         if (g_settings_get_boolean (MainSettings, "id3v2-compression"))
1042         {
1043             id3_tag_options (v2tag, ID3_TAG_OPTION_COMPRESSION, ~0);
1044         }
1045     }
1046 
1047     /* Write ID3v1 tag. */
1048     if (g_settings_get_boolean (MainSettings, "id3v1-enabled"))
1049     {
1050         v1tag = id3_tag_new();
1051         if (!v1tag)
1052         {
1053             g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
1054                          _("Error reading tags from file"));
1055             return FALSE;
1056         }
1057 
1058         id3_tag_options(v1tag, ID3_TAG_OPTION_ID3V1, ~0);
1059     }
1060 
1061 
1062     /*********
1063      * Title *
1064      *********/
1065     etag_set_tags(FileTag->title, ID3_FRAME_TITLE, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, &strip_tags);
1066 
1067     /**********
1068      * Artist *
1069      **********/
1070     etag_set_tags(FileTag->artist, ID3_FRAME_ARTIST, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, &strip_tags);
1071 
1072     /**********
1073      * Album Artist *
1074      **********/
1075     etag_set_tags(FileTag->album_artist, "TPE2", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, &strip_tags);
1076 
1077     /*********
1078      * Album *
1079      *********/
1080     etag_set_tags(FileTag->album, ID3_FRAME_ALBUM, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, &strip_tags);
1081 
1082     /***************
1083      * Part of set *
1084      ***************/
1085     string1 = et_id3tag_get_tpos_from_file_tag (FileTag);
1086     etag_set_tags (string1, "TPOS", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag,
1087                    &strip_tags);
1088     g_free (string1);
1089 
1090     /********
1091      * Year *
1092      ********/
1093     etag_set_tags(FileTag->year, ID3_FRAME_YEAR, ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, &strip_tags);
1094 
1095     /*************************
1096      * Track and Total Track *
1097      *************************/
1098     if ( FileTag->track
1099     &&   FileTag->track_total
1100     &&  *FileTag->track_total )
1101         string1 = g_strconcat(FileTag->track,"/",FileTag->track_total,NULL);
1102     else
1103         string1 = NULL;
1104 
1105     etag_set_tags(string1 ? string1 : FileTag->track, ID3_FRAME_TRACK, ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, &strip_tags);
1106     etag_set_tags(FileTag->track, ID3_FRAME_TRACK, ID3_FIELD_TYPE_STRINGLIST, v1tag, NULL, &strip_tags);
1107     g_free(string1);
1108 
1109     /*********
1110      * Genre *
1111      *********/
1112     /* Genre is written like this :
1113      *    - "<genre_id>"    -> "3"
1114      *    - "<genre_name>"  -> "EuroDance"
1115      */
1116     if (FileTag->genre)
1117         genre_value = Id3tag_String_To_Genre(FileTag->genre);
1118 
1119     if ((genre_value == ID3_INVALID_GENRE)
1120         || g_settings_get_boolean (MainSettings, "id3v2-text-only-genre"))
1121     {
1122         etag_set_tags (FileTag->genre, ID3_FRAME_GENRE,
1123                        ID3_FIELD_TYPE_STRINGLIST, v1tag, v2tag, &strip_tags);
1124     }
1125     else
1126     {
1127         /* The ID3v1 genre must always be given as a plain string, and
1128          * libid3tag does the appropriate conversion. */
1129         etag_set_tags (FileTag->genre, ID3_FRAME_GENRE,
1130                        ID3_FIELD_TYPE_STRINGLIST, v1tag, NULL, &strip_tags);
1131 
1132         /* Only the ID3v2 tag is converted to the bracketed form. */
1133         string1 = g_strdup_printf ("(%d)",genre_value);
1134         etag_set_tags (string1, ID3_FRAME_GENRE,
1135                        ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, &strip_tags);
1136         g_free (string1);
1137     }
1138 
1139     /***********
1140      * Comment *
1141      ***********/
1142     etag_set_tags(FileTag->comment, ID3_FRAME_COMMENT, ID3_FIELD_TYPE_STRINGFULL, v1tag, v2tag, &strip_tags);
1143 
1144     /************
1145      * Composer *
1146      ************/
1147     etag_set_tags(FileTag->composer, "TCOM", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, &strip_tags);
1148 
1149     /*******************
1150      * Original artist *
1151      *******************/
1152     etag_set_tags(FileTag->orig_artist, "TOPE", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, &strip_tags);
1153 
1154     /*************
1155      * Copyright *
1156      *************/
1157     etag_set_tags(FileTag->copyright, "TCOP", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, &strip_tags);
1158 
1159     /*******
1160      * URL *
1161      *******/
1162     etag_set_tags(FileTag->url, "WXXX", ID3_FIELD_TYPE_LATIN1, NULL, v2tag, &strip_tags);
1163 
1164     /***************
1165      * Encoded by  *
1166      ***************/
1167     //if ( v2tag && FileTag->encoded_by && *FileTag->encoded_by
1168     //&& (frame = Id3tag_find_and_create_txxframe(v2tag, EASYTAG_STRING_ENCODEDBY)))
1169     //{
1170     //    id3taglib_set_field(frame, EASYTAG_STRING_ENCODEDBY, ID3_FIELD_TYPE_STRING, 0, 1, 0);
1171     //    id3taglib_set_field(frame, FileTag->encoded_by, ID3_FIELD_TYPE_STRING, 1, 0, 0);
1172     //    strip_tags = FALSE;
1173     //}else
1174     // Save encoder name in TENC frame instead of the TXX frame
1175     etag_set_tags(FileTag->encoded_by, "TENC", ID3_FIELD_TYPE_STRINGLIST, NULL, v2tag, &strip_tags);
1176     if (v2tag)
1177         Id3tag_delete_txxframes(v2tag, EASYTAG_STRING_ENCODEDBY, 0);
1178 
1179     /***********
1180      * Picture *
1181      ***********/
1182     Id3tag_delete_frames(v2tag, "APIC", 0);
1183 
1184     if (v2tag)
1185     {
1186         for (pic = FileTag->picture; pic != NULL; pic = pic->next)
1187         {
1188             gint i;
1189 
1190             if ((frame = id3_frame_new("APIC")) == NULL)
1191                 continue;
1192 
1193             id3_tag_attachframe(v2tag, frame);
1194             for (i = 0; (field = id3_frame_field(frame, i)); i++)
1195             {
1196                 Picture_Format format;
1197                 enum id3_field_type field_type;
1198 
1199                 field_type = id3_field_type (field);
1200 
1201                 if (field_type == ID3_FIELD_TYPE_LATIN1)
1202                 {
1203                     format = Picture_Format_From_Data(pic);
1204                     id3_field_setlatin1(field, (id3_latin1_t const *)Picture_Mime_Type_String(format));
1205                 }
1206                 else if (field_type == ID3_FIELD_TYPE_INT8)
1207                 {
1208                     id3_field_setint (field, pic->type);
1209                 }
1210                 else if (field_type == ID3_FIELD_TYPE_BINARYDATA)
1211                 {
1212                     gconstpointer data;
1213                     gsize data_size;
1214 
1215                     data = g_bytes_get_data (pic->bytes, &data_size);
1216                     id3_field_setbinarydata (field, data, data_size);
1217                 }
1218             }
1219 
1220             if (pic->description)
1221                 id3taglib_set_field(frame, pic->description, ID3_FIELD_TYPE_STRING, 0, 0, 0);
1222 
1223             strip_tags = FALSE;
1224         }
1225     }
1226 
1227     /****************************************
1228      * File length (in milliseconds) DISCARD*
1229      ****************************************/
1230 
1231     /*********************************
1232      * Update id3v1.x and id3v2 tags *
1233      *********************************/
1234     success = etag_write_tags (filename, v1tag, v2tag, strip_tags, error);
1235 
1236     // Free data
1237     if (v1tag)
1238         id3_tag_delete(v1tag);
1239     if (v2tag)
1240         id3_tag_delete(v2tag);
1241 
1242     return success;
1243 }
1244 
1245 /* Dele all frames with 'name'
1246  * begining with frame num 'start' (0-based)
1247  * from tag 'tag'
1248  */
1249 static void
Id3tag_delete_frames(struct id3_tag * tag,const gchar * name,int start)1250 Id3tag_delete_frames(struct id3_tag *tag, const gchar *name, int start)
1251 {
1252     struct id3_frame *frame;
1253 
1254     if (!tag || !name || !*name)
1255     return;
1256 
1257     while ((frame = id3_tag_findframe(tag, name, start)))
1258     {
1259         id3_tag_detachframe(tag, frame);
1260         id3_frame_delete(frame);
1261     }
1262 
1263 }
1264 
1265 static void
Id3tag_delete_txxframes(struct id3_tag * tag,const gchar * param1,int start)1266 Id3tag_delete_txxframes(struct id3_tag *tag, const gchar *param1, int start)
1267 {
1268     int i;
1269     struct id3_frame *frame;
1270     union id3_field *field;
1271     const id3_ucs4_t *ucs4string;
1272     gchar *str;
1273 
1274     if (!tag || !param1 || !*param1)
1275     return;
1276 
1277     for (i = start; (frame = id3_tag_findframe(tag, "TXXX", i)); )
1278         if ( (field = id3_frame_field(frame, 1))
1279         && (ucs4string = id3_field_getstring(field)) )
1280         {
1281             str = NULL;
1282             if ((str = (gchar *)id3_ucs4_latin1duplicate(ucs4string))
1283             && (g_ascii_strncasecmp (str, param1, strlen (param1)) == 0))
1284             {
1285                 g_free(str);
1286                 id3_tag_detachframe(tag, frame);
1287                 id3_frame_delete(frame);
1288             }else
1289             {
1290                 i++;
1291                 g_free(str);
1292             }
1293         }else
1294             i++;
1295 }
1296 
1297 /* Find first frame with name 'name' in tag 'tag'
1298  * create new if not found
1299  */
1300 static struct id3_frame *
Id3tag_find_and_create_frame(struct id3_tag * tag,const gchar * name)1301 Id3tag_find_and_create_frame (struct id3_tag *tag, const gchar *name)
1302 {
1303     struct id3_frame *frame;
1304 
1305     g_return_val_if_fail (tag != NULL && name != NULL && *name != 0, NULL);
1306 
1307     frame = id3_tag_findframe(tag, name, 0);
1308     if (!frame)
1309     {
1310         if ((frame = id3_frame_new(name)) == NULL)
1311             return NULL;
1312         id3_tag_attachframe(tag, frame);
1313     }
1314 
1315     return frame;
1316 }
1317 
1318 static int
id3taglib_set_field(struct id3_frame * frame,const gchar * str,enum id3_field_type type,int num,int clear,int id3v1)1319 id3taglib_set_field(struct id3_frame *frame,
1320                     const gchar *str,
1321                     enum id3_field_type type,
1322                     int num, int clear, int id3v1)
1323 {
1324     union id3_field    *field;
1325     enum id3_field_type    curtype;
1326     id3_ucs4_t        *buf;
1327     gchar        *latinstr, *encname;
1328     enum id3_field_textencoding enc_field;
1329     unsigned    i;
1330     unsigned    is_set;
1331 
1332     latinstr = NULL, buf = NULL;
1333     is_set = 0;
1334     enc_field = ID3_FIELD_TEXTENCODING_ISO_8859_1;
1335 
1336     if (str)
1337     {
1338         /* Prepare str according to encoding conversion settings. */
1339         if ((!g_settings_get_boolean (MainSettings, "id3v2-enable-unicode"))
1340             || (type == ID3_FIELD_TYPE_LATIN1)
1341             || (type == ID3_FIELD_TYPE_LATIN1FULL)
1342             || id3v1)
1343         {
1344             encname = NULL;
1345             /* id3v1 fields converted using its own character set and iconv options */
1346             if ( id3v1 )
1347             {
1348                 gint id3v1_charset;
1349                 const gchar *charset;
1350                 EtTagEncoding iconv_option;
1351 
1352                 id3v1_charset = g_settings_get_enum (MainSettings,
1353                                                      "id3v1-charset");
1354                 charset = et_charset_get_name_from_index (id3v1_charset);
1355                 iconv_option = g_settings_get_enum (MainSettings,
1356                                                     "id3v1-encoding-option");
1357 
1358                 if (iconv_option != ET_TAG_ENCODING_NONE)
1359                 {
1360                     encname = g_strconcat (charset,
1361                                            iconv_option == ET_TAG_ENCODING_TRANSLITERATE ? "//TRANSLIT" : "//IGNORE",
1362                                            NULL);
1363                 }
1364                 else
1365                 {
1366                     encname = g_strdup (charset);
1367                 }
1368             }
1369             else
1370             {
1371                 /* latin1 fields (such as URL) always converted with ISO-8859-1*/
1372                 if ((type != ID3_FIELD_TYPE_LATIN1) && (type != ID3_FIELD_TYPE_LATIN1FULL))
1373                 {
1374                     gint id3v2_charset;
1375                     const gchar *charset;
1376                     EtTagEncoding iconv_option;
1377 
1378                     id3v2_charset = g_settings_get_enum (MainSettings,
1379                                                          "id3v2-no-unicode-charset");
1380                     charset = et_charset_get_name_from_index (id3v2_charset);
1381                     iconv_option = g_settings_get_enum (MainSettings,
1382                                                         "id3v2-encoding-option");
1383                     if (iconv_option != ET_TAG_ENCODING_NONE)
1384                     {
1385                         encname = g_strconcat (charset,
1386                                                iconv_option == ET_TAG_ENCODING_TRANSLITERATE ? "//TRANSLIT" : "//IGNORE",
1387                                                NULL);
1388                     }
1389                     else
1390                     {
1391                         encname = g_strdup (charset);
1392                     }
1393                 }
1394             }
1395 
1396             latinstr = convert_string(str, "UTF-8", encname ? encname : "ISO-8859-1//IGNORE", TRUE);
1397             g_free (encname);
1398             buf = id3_latin1_ucs4duplicate((id3_latin1_t const *)latinstr);
1399         }
1400         else
1401         {
1402             gchar *charset;
1403 
1404             charset = g_settings_get_string (MainSettings,
1405                                              "id3v2-unicode-charset");
1406 
1407             if (!strcmp (charset, "UTF-16"))
1408             {
1409                 enc_field = ID3_FIELD_TEXTENCODING_UTF_16;
1410                 buf = id3_utf8_ucs4duplicate((id3_utf8_t const *)str);
1411             }
1412             else
1413             {
1414                 enc_field = ID3_FIELD_TEXTENCODING_UTF_8;
1415                 buf = id3_utf8_ucs4duplicate((id3_utf8_t const *)str);
1416             }
1417 
1418             g_free (charset);
1419         }
1420     }
1421 
1422     if (frame)
1423         frame->flags &= ~ID3_FRAME_FLAG_FORMATFLAGS;
1424 
1425     for (i = 0; (field = id3_frame_field(frame, i)); i++)
1426     {
1427         if (is_set && !clear)
1428             break;
1429 
1430         curtype = id3_field_type (field);
1431 
1432         if (curtype == ID3_FIELD_TYPE_TEXTENCODING)
1433         {
1434             id3_field_settextencoding (field, enc_field);
1435         }
1436         else if (curtype == ID3_FIELD_TYPE_LATIN1)
1437         {
1438             if (clear)
1439             {
1440                 id3_field_setlatin1 (field, NULL);
1441             }
1442 
1443             if ((type == curtype) && !is_set)
1444             {
1445                 if (num == 0)
1446                 {
1447                     id3_field_setlatin1 (field,
1448                                          (id3_latin1_t const *)latinstr);
1449                     is_set = 1;
1450                 }
1451                 else
1452                 {
1453                     num--;
1454                 }
1455             }
1456         }
1457         else if (curtype == ID3_FIELD_TYPE_LATIN1FULL)
1458         {
1459                 if (clear)
1460                 {
1461                     id3_field_setfulllatin1 (field, NULL);
1462                 }
1463                 if ((type == curtype) && !is_set)
1464                 {
1465                     if (num == 0)
1466                     {
1467                         id3_field_setfulllatin1 (field,
1468                                                  (id3_latin1_t const *)latinstr);
1469                         is_set = 1;
1470                     }
1471                     else
1472                     {
1473                         num--;
1474                     }
1475                 }
1476         }
1477         else if (curtype == ID3_FIELD_TYPE_STRING)
1478         {
1479                 if (clear)
1480                 {
1481                     id3_field_setstring (field, NULL);
1482                 }
1483 
1484                 if ((type == curtype) && !is_set)
1485                 {
1486                     if (num == 0)
1487                     {
1488                         id3_field_setstring(field, buf);
1489                         is_set = 1;
1490                     }
1491                     else
1492                     {
1493                         num--;
1494                     }
1495                 }
1496         }
1497         else if (curtype == ID3_FIELD_TYPE_STRINGFULL)
1498         {
1499             if (clear)
1500             {
1501                 id3_field_setfullstring (field, NULL);
1502             }
1503 
1504             if ((type == curtype) && !is_set)
1505             {
1506                 if (num == 0)
1507                 {
1508                     id3_field_setfullstring (field, buf);
1509                     is_set = 1;
1510                 }
1511                 else
1512                 {
1513                     num--;
1514                 }
1515             }
1516         }
1517         else if (curtype == ID3_FIELD_TYPE_STRINGLIST)
1518         {
1519             if (clear)
1520             {
1521                 id3_field_setstrings (field, 0, NULL);
1522             }
1523 
1524             if ((type == curtype) && !is_set)
1525             {
1526                 if ((num == 0) && (buf))
1527                 {
1528                     id3_field_addstring (field, buf);
1529                     is_set = 1;
1530                 }
1531                 else
1532                 {
1533                     num--;
1534                 }
1535             }
1536         }
1537 
1538         if (is_set)
1539         {
1540             free(latinstr);
1541             free(buf);
1542             latinstr = NULL, buf = NULL;
1543         }
1544     }
1545 
1546     if (latinstr || buf)
1547     {
1548         free(latinstr);
1549         free(buf);
1550         return 1;
1551     } else
1552         return 0;
1553 }
1554 
1555 
1556 static int
etag_set_tags(const gchar * str,const char * frame_name,enum id3_field_type field_type,struct id3_tag * v1tag,struct id3_tag * v2tag,gboolean * strip_tags)1557 etag_set_tags (const gchar *str,
1558                const char *frame_name,
1559                enum id3_field_type field_type,
1560                struct id3_tag *v1tag,
1561                struct id3_tag *v2tag,
1562               gboolean *strip_tags)
1563 {
1564     struct id3_frame *ftmp;
1565 
1566     if ( str && *str )
1567     {
1568         *strip_tags = FALSE;
1569 
1570         if (v2tag
1571         && (ftmp = Id3tag_find_and_create_frame(v2tag, frame_name)))
1572             id3taglib_set_field(ftmp, str, field_type, 0, 1, 0);
1573         if (v1tag
1574         && (ftmp = Id3tag_find_and_create_frame(v1tag, frame_name)))
1575             id3taglib_set_field(ftmp, str, field_type, 0, 1, 1);
1576     }else
1577     {
1578         if (v2tag)
1579             Id3tag_delete_frames(v2tag, frame_name, 0);
1580     }
1581 
1582     return 0;
1583 }
1584 
1585 static gboolean
etag_write_tags(const gchar * filename,struct id3_tag const * v1tag,struct id3_tag const * v2tag,gboolean strip_tags,GError ** error)1586 etag_write_tags (const gchar *filename,
1587                  struct id3_tag const *v1tag,
1588                  struct id3_tag const *v2tag,
1589                  gboolean strip_tags,
1590                  GError **error)
1591 {
1592     id3_byte_t *v1buf, *v2buf;
1593     id3_length_t v1size = 0, v2size = 0;
1594     gchar tmp[ID3_TAG_QUERYSIZE];
1595     GFile *file;
1596     GFileIOStream *iostream;
1597     GSeekable *seekable;
1598     GInputStream *istream;
1599     GOutputStream *ostream;
1600     long filev2size;
1601     gchar *audio_buffer = NULL;
1602     gboolean success = TRUE;
1603     gsize bytes_read;
1604     gsize bytes_written;
1605 
1606     v1buf = v2buf = NULL;
1607 
1608     if (!strip_tags)
1609     {
1610         /* Render v1 tag */
1611         if (v1tag)
1612         {
1613             v1size = id3_tag_render (v1tag, NULL);
1614 
1615             if (v1size == ID3V1_TAG_SIZE)
1616             {
1617                 v1buf = g_malloc (v1size);
1618 
1619                 if (id3_tag_render (v1tag, v1buf) != v1size)
1620                 {
1621                     /* NOTREACHED */
1622                     g_free (v1buf);
1623                     v1buf = NULL;
1624                 }
1625             }
1626         }
1627 
1628         /* Render v2 tag */
1629         if (v2tag)
1630         {
1631             v2size = id3_tag_render (v2tag, NULL);
1632 
1633             if (v2size > 10)
1634             {
1635                 v2buf = g_malloc0 (v2size);
1636 
1637                 if ((v2size = id3_tag_render (v2tag, v2buf)) == 0)
1638                 {
1639                     /* NOTREACHED */
1640                     g_free (v2buf);
1641                     v2buf = NULL;
1642                 }
1643             }
1644         }
1645     }
1646 
1647     if (v1buf == NULL)
1648     {
1649         v1size = 0;
1650     }
1651     if (v2buf == NULL)
1652     {
1653         v2size = 0;
1654     }
1655 
1656     file = g_file_new_for_path (filename);
1657     iostream = g_file_open_readwrite (file, NULL, error);
1658 
1659     if (!iostream)
1660     {
1661         goto err;
1662     }
1663 
1664     /* Seeking on the IOStream seeks to the same position on both the input and
1665      * output streams. */
1666     seekable = G_SEEKABLE (iostream);
1667 
1668     if (!g_seekable_can_seek (seekable))
1669     {
1670         g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_BADF, "%s",
1671                      g_strerror (EBADF));
1672         goto err;
1673     }
1674 
1675     success = FALSE;
1676 
1677     /* Handle ID3v1 tag */
1678     if (!g_seekable_seek (seekable, -ID3V1_TAG_SIZE, G_SEEK_END, NULL, error))
1679     {
1680         goto err;
1681     }
1682 
1683     istream = g_io_stream_get_input_stream (G_IO_STREAM (iostream));
1684 
1685     if (!g_input_stream_read_all (istream, tmp, ID3_TAG_QUERYSIZE, &bytes_read,
1686                                   NULL, error))
1687     {
1688         goto err;
1689     }
1690 
1691     /* Seek to the beginning of the ID3v1 tag, if it exists. */
1692     if ((tmp[0] == 'T') && (tmp[1] == 'A') && (tmp[2] == 'G'))
1693     {
1694         if (!g_seekable_seek (seekable, -ID3V1_TAG_SIZE, G_SEEK_END, NULL,
1695                               error))
1696         {
1697             goto err;
1698         }
1699     }
1700     else
1701     {
1702         if (!g_seekable_seek (seekable, 0, G_SEEK_END, NULL, error))
1703         {
1704             goto err;
1705         }
1706     }
1707 
1708     /* Search ID3v2 tags at the end of the file (before any ID3v1 tag) */
1709     /* XXX: Unsafe */
1710     if (g_seekable_seek (seekable, -ID3_TAG_QUERYSIZE, G_SEEK_CUR, NULL,
1711                          error))
1712     {
1713         if (!g_input_stream_read_all (istream, tmp, ID3_TAG_QUERYSIZE,
1714                                       &bytes_read, NULL, error))
1715         {
1716             goto err;
1717         }
1718 
1719         filev2size = id3_tag_query ((id3_byte_t const *)tmp,
1720                                     ID3_TAG_QUERYSIZE);
1721 
1722         if (filev2size > 10)
1723         {
1724             if (!g_seekable_seek (seekable, -filev2size, G_SEEK_CUR, NULL,
1725                                   error))
1726             {
1727                 goto err;
1728             }
1729 
1730             if (!g_input_stream_read_all (istream, tmp, ID3_TAG_QUERYSIZE,
1731                                           &bytes_read, NULL, error))
1732             {
1733                 goto err;
1734             }
1735 
1736             if (id3_tag_query ((id3_byte_t const *)tmp, ID3_TAG_QUERYSIZE)
1737                 != filev2size)
1738             {
1739                 if (!g_seekable_seek (seekable,
1740                                       -ID3_TAG_QUERYSIZE - filev2size,
1741                                       G_SEEK_CUR, NULL, error))
1742                 {
1743                     goto err;
1744                 }
1745             }
1746             else
1747             {
1748                 if (!g_seekable_seek (seekable, -ID3_TAG_QUERYSIZE,
1749                                       G_SEEK_CUR, NULL, error))
1750                 {
1751                     goto err;
1752                 }
1753             }
1754         }
1755     }
1756 
1757     ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
1758 
1759     /* Write id3v1 tag */
1760     if (v1buf)
1761     {
1762         if (!g_output_stream_write_all (ostream, v1buf, v1size, &bytes_written,
1763                                         NULL, error))
1764         {
1765             goto err;
1766         }
1767     }
1768 
1769     /* Truncate file (strip tags at the end of file) */
1770     if (!g_seekable_can_truncate (seekable))
1771     {
1772         g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_BADF, "%s",
1773                      g_strerror (EBADF));
1774         goto err;
1775     }
1776 
1777     if (!g_seekable_truncate (seekable, g_seekable_tell (seekable), NULL,
1778                               error))
1779     {
1780         goto err;
1781     }
1782 
1783     /* Handle Id3v2 tag */
1784     if (!g_seekable_seek (seekable, 0, G_SEEK_SET, NULL, error))
1785     {
1786         goto err;
1787     }
1788 
1789     if (!g_input_stream_read_all (istream, tmp, ID3_TAG_QUERYSIZE, &bytes_read,
1790                                   NULL, error))
1791     {
1792         goto err;
1793     }
1794 
1795     filev2size = id3_tag_query ((id3_byte_t const *)tmp, ID3_TAG_QUERYSIZE);
1796 
1797     /* No ID3v2 tag in the file, and no new tag. */
1798     if ((filev2size == 0) && (v2size == 0))
1799     {
1800         /* TODO: Improve error description. */
1801         g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_BADF, "%s",
1802                      g_strerror (EBADF));
1803         goto err;
1804     }
1805 
1806     if (filev2size == (long)v2size)
1807     {
1808         /* New and old tag are the same length, so no need to handle audio. */
1809         if (!g_seekable_seek (seekable, 0, G_SEEK_SET, NULL, error))
1810         {
1811             goto err;
1812         }
1813 
1814         if (!g_output_stream_write_all (ostream, v2buf, v2size, &bytes_written,
1815                                         NULL, error))
1816         {
1817             goto err;
1818         }
1819     }
1820     else
1821     {
1822         gsize audio_length;
1823 
1824         /* New and old tag differ in length, so copy the audio data to after
1825          * the new tag. */
1826         if (!g_seekable_seek (seekable, 0, G_SEEK_END, NULL, error))
1827         {
1828             goto err;
1829         }
1830 
1831         audio_length = g_seekable_tell (seekable) - filev2size;
1832         audio_buffer = g_malloc (audio_length);
1833 
1834         if (!g_seekable_seek (seekable, filev2size, G_SEEK_SET, NULL, error))
1835         {
1836             goto err;
1837         }
1838 
1839         if (audio_length != 0)
1840         {
1841             if (!g_input_stream_read_all (istream, audio_buffer, audio_length,
1842                                           &bytes_read, NULL, error))
1843             {
1844                 goto err;
1845             }
1846         }
1847 
1848         /* Return to the beginning of the file. */
1849         if (!g_seekable_seek (seekable, 0, G_SEEK_SET, NULL, error))
1850         {
1851             goto err;
1852         }
1853 
1854         /* Write the ID3v2 tag. */
1855         if (v2buf)
1856         {
1857             if (!g_output_stream_write_all (ostream, v2buf, v2size,
1858                                             &bytes_written, NULL, error))
1859             {
1860                 goto err;
1861             }
1862         }
1863 
1864         /* Write audio data. */
1865         if (audio_length != 0)
1866         {
1867             if (!g_output_stream_write_all (ostream, audio_buffer,
1868                                             audio_length, &bytes_written, NULL,
1869                                             error))
1870             {
1871                 goto err;
1872             }
1873         }
1874 
1875         if (!g_seekable_truncate (seekable, g_seekable_tell (seekable), NULL,
1876                                   error))
1877         {
1878             goto err;
1879         }
1880     }
1881 
1882     success = TRUE;
1883 
1884 err:
1885     g_free (audio_buffer);
1886     g_object_unref (file);
1887     g_clear_object (&iostream);
1888     g_free (v1buf);
1889     g_free (v2buf);
1890     return success;
1891 }
1892 
1893 #endif /* ENABLE_MP3 */
1894