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