1 /*
2 * Copyright (C) 2006, Jamie McCracken <jamiemcc@gnome.org>
3 * Copyright (C) 2008-2009, Nokia <ivan.frade@nokia.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22
23 #ifndef _GNU_SOURCE
24 #define _GNU_SOURCE
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <errno.h>
35
36 #include <glib.h>
37 #include <glib/gstdio.h>
38
39 #ifndef G_OS_WIN32
40 #include <sys/mman.h>
41 #endif /* G_OS_WIN32 */
42
43 #include <libtracker-common/tracker-common.h>
44
45 #include <libtracker-extract/tracker-extract.h>
46
47 #include "tracker-media-art.h"
48
49 #ifdef FRAME_ENABLE_TRACE
50 #warning Frame traces enabled
51 #endif /* FRAME_ENABLE_TRACE */
52
53 /* We mmap the beginning of the file and read separately the last 128
54 * bytes for id3v1 tags. While these are probably cornercases the
55 * rationale is that we don't want to fault a whole page for the last
56 * 128 bytes and on the other we don't want to mmap the whole file
57 * with unlimited size (might need to create private copy in some
58 * special cases, finding continuous space etc). We now take 5 first
59 * MB of the file and assume that this is enough. In theory there is
60 * no maximum size as someone could embed 50 gigabytes of album art
61 * there.
62 */
63
64 #define MAX_FILE_READ 1024 * 1024 * 5
65 #define MAX_MP3_SCAN_DEEP 16768
66
67 #define MAX_FRAMES_SCAN 512
68 #define VBR_THRESHOLD 16
69
70 #define ID3V1_SIZE 128
71
72 typedef struct {
73 gchar *title;
74 gchar *artist;
75 gchar *album;
76 gchar *recording_time;
77 gchar *comment;
78 gchar *genre;
79 gchar *encoding;
80 gint track_number;
81 } id3tag;
82
83 typedef struct {
84 gchar *album;
85 gchar *comment;
86 gchar *content_type;
87 gchar *copyright;
88 gchar *encoded_by;
89 guint32 length;
90 gchar *performer1;
91 gchar *performer2;
92 gchar *composer;
93 gchar *publisher;
94 gchar *recording_time;
95 gchar *release_time;
96 gchar *text, *toly;
97 gchar *title1;
98 gchar *title2;
99 gchar *title3;
100 gint track_number;
101 gint track_count;
102 gint set_number;
103 gint set_count;
104 } id3v2tag;
105
106 typedef enum {
107 ID3V2_UNKNOWN,
108 ID3V2_COM,
109 ID3V2_PIC,
110 ID3V2_TAL,
111 ID3V2_TCO,
112 ID3V2_TCR,
113 ID3V2_TEN,
114 ID3V2_TLE,
115 ID3V2_TPB,
116 ID3V2_TP1,
117 ID3V2_TP2,
118 ID3V2_TRK,
119 ID3V2_TT1,
120 ID3V2_TT2,
121 ID3V2_TT3,
122 ID3V2_TXT,
123 ID3V2_TYE,
124 } id3v2frame;
125
126 typedef enum {
127 ID3V24_UNKNOWN,
128 ID3V24_APIC,
129 ID3V24_COMM,
130 ID3V24_TALB,
131 ID3V24_TCOM,
132 ID3V24_TCON,
133 ID3V24_TCOP,
134 ID3V24_TDRC,
135 ID3V24_TDRL,
136 ID3V24_TENC,
137 ID3V24_TEXT,
138 ID3V24_TIT1,
139 ID3V24_TIT2,
140 ID3V24_TIT3,
141 ID3V24_TLEN,
142 ID3V24_TOLY,
143 ID3V24_TPE1,
144 ID3V24_TPE2,
145 ID3V24_TPUB,
146 ID3V24_TRCK,
147 ID3V24_TPOS,
148 ID3V24_TYER,
149 } id3v24frame;
150
151 typedef struct {
152 size_t size;
153 size_t id3v2_size;
154
155 const gchar *title;
156 const gchar *performer;
157 gchar *performer_uri;
158 const gchar *lyricist;
159 gchar *lyricist_uri;
160 const gchar *album;
161 gchar *album_uri;
162 const gchar *genre;
163 const gchar *text;
164 const gchar *recording_time;
165 const gchar *encoded_by;
166 const gchar *copyright;
167 const gchar *publisher;
168 const gchar *comment;
169 const gchar *composer;
170 gchar *composer_uri;
171 gint track_number;
172 gint track_count;
173 gint set_number;
174 gint set_count;
175
176 unsigned char *media_art_data;
177 size_t media_art_size;
178 gchar *media_art_mime;
179
180 id3tag id3v1;
181 id3v2tag id3v22;
182 id3v2tag id3v23;
183 id3v2tag id3v24;
184 } MP3Data;
185
186 enum {
187 MPEG_ERR,
188 MPEG_V1,
189 MPEG_V2,
190 MPEG_V25
191 };
192
193 enum {
194 LAYER_ERR,
195 LAYER_1,
196 LAYER_2,
197 LAYER_3
198 };
199
200 /* sorted array */
201 static const struct {
202 const char *name;
203 id3v24frame frame;
204 } id3v24_frames[] = {
205 { "APIC", ID3V24_APIC },
206 { "COMM", ID3V24_COMM },
207 { "TALB", ID3V24_TALB },
208 { "TCOM", ID3V24_TCOM },
209 { "TCON", ID3V24_TCON },
210 { "TCOP", ID3V24_TCOP },
211 { "TDRC", ID3V24_TDRC },
212 { "TDRL", ID3V24_TDRL },
213 { "TENC", ID3V24_TENC },
214 { "TEXT", ID3V24_TEXT },
215 { "TIT1", ID3V24_TIT1 },
216 { "TIT2", ID3V24_TIT2 },
217 { "TIT3", ID3V24_TIT3 },
218 { "TLEN", ID3V24_TLEN },
219 { "TOLY", ID3V24_TOLY },
220 { "TPE1", ID3V24_TPE1 },
221 { "TPE2", ID3V24_TPE2 },
222 { "TPOS", ID3V24_TPOS },
223 { "TPUB", ID3V24_TPUB },
224 { "TRCK", ID3V24_TRCK },
225 { "TYER", ID3V24_TYER },
226 };
227
228 /* sorted array */
229 static const struct {
230 const char *name;
231 id3v2frame frame;
232 } id3v2_frames[] = {
233 { "COM", ID3V2_COM },
234 { "PIC", ID3V2_PIC },
235 { "TAL", ID3V2_TAL },
236 { "TCO", ID3V2_TCO },
237 { "TCR", ID3V2_TCR },
238 { "TEN", ID3V2_TEN },
239 { "TLE", ID3V2_TLE },
240 { "TP1", ID3V2_TP1 },
241 { "TP2", ID3V2_TP2 },
242 { "TPB", ID3V2_TPB },
243 { "TRK", ID3V2_TRK },
244 { "TT1", ID3V2_TT1 },
245 { "TT2", ID3V2_TT2 },
246 { "TT3", ID3V2_TT3 },
247 { "TXT", ID3V2_TXT },
248 { "TYE", ID3V2_TYE },
249 };
250
251 static const char *const genre_names[] = {
252 "Blues",
253 "Classic Rock",
254 "Country",
255 "Dance",
256 "Disco",
257 "Funk",
258 "Grunge",
259 "Hip-Hop",
260 "Jazz",
261 "Metal",
262 "New Age",
263 "Oldies",
264 "Other",
265 "Pop",
266 "R&B",
267 "Rap",
268 "Reggae",
269 "Rock",
270 "Techno",
271 "Industrial",
272 "Alternative",
273 "Ska",
274 "Death Metal",
275 "Pranks",
276 "Soundtrack",
277 "Euro-Techno",
278 "Ambient",
279 "Trip-Hop",
280 "Vocal",
281 "Jazz+Funk",
282 "Fusion",
283 "Trance",
284 "Classical",
285 "Instrumental",
286 "Acid",
287 "House",
288 "Game",
289 "Sound Clip",
290 "Gospel",
291 "Noise",
292 "Alt. Rock",
293 "Bass",
294 "Soul",
295 "Punk",
296 "Space",
297 "Meditative",
298 "Instrumental Pop",
299 "Instrumental Rock",
300 "Ethnic",
301 "Gothic",
302 "Darkwave",
303 "Techno-Industrial",
304 "Electronic",
305 "Pop-Folk",
306 "Eurodance",
307 "Dream",
308 "Southern Rock",
309 "Comedy",
310 "Cult",
311 "Gangsta Rap",
312 "Top 40",
313 "Christian Rap",
314 "Pop/Funk",
315 "Jungle",
316 "Native American",
317 "Cabaret",
318 "New Wave",
319 "Psychedelic",
320 "Rave",
321 "Showtunes",
322 "Trailer",
323 "Lo-Fi",
324 "Tribal",
325 "Acid Punk",
326 "Acid Jazz",
327 "Polka",
328 "Retro",
329 "Musical",
330 "Rock & Roll",
331 "Hard Rock",
332 "Folk",
333 "Folk/Rock",
334 "National Folk",
335 "Swing",
336 "Fast-Fusion",
337 "Bebob",
338 "Latin",
339 "Revival",
340 "Celtic",
341 "Bluegrass",
342 "Avantgarde",
343 "Gothic Rock",
344 "Progressive Rock",
345 "Psychedelic Rock",
346 "Symphonic Rock",
347 "Slow Rock",
348 "Big Band",
349 "Chorus",
350 "Easy Listening",
351 "Acoustic",
352 "Humour",
353 "Speech",
354 "Chanson",
355 "Opera",
356 "Chamber Music",
357 "Sonata",
358 "Symphony",
359 "Booty Bass",
360 "Primus",
361 "Porn Groove",
362 "Satire",
363 "Slow Jam",
364 "Club",
365 "Tango",
366 "Samba",
367 "Folklore",
368 "Ballad",
369 "Power Ballad",
370 "Rhythmic Soul",
371 "Freestyle",
372 "Duet",
373 "Punk Rock",
374 "Drum Solo",
375 "A Cappella",
376 "Euro-House",
377 "Dance Hall",
378 "Goa",
379 "Drum & Bass",
380 "Club-House",
381 "Hardcore",
382 "Terror",
383 "Indie",
384 "BritPop",
385 "Negerpunk",
386 "Polsk Punk",
387 "Beat",
388 "Christian Gangsta Rap",
389 "Heavy Metal",
390 "Black Metal",
391 "Crossover",
392 "Contemporary Christian",
393 "Christian Rock",
394 "Merengue",
395 "Salsa",
396 "Thrash Metal",
397 "Anime",
398 "JPop",
399 "Synthpop"
400 };
401
402 static const guint sync_mask = 0xE0FF;
403 static const guint mpeg_ver_mask = 0x1800;
404 static const guint mpeg_layer_mask = 0x600;
405 static const guint bitrate_mask = 0xF00000;
406 static const guint freq_mask = 0xC0000;
407 static const guint ch_mask = 0xC0000000;
408 static const guint pad_mask = 0x20000;
409
410 static gint bitrate_table[16][6] = {
411 { 0, 0, 0, 0, 0, 0 },
412 { 32, 32, 32, 32, 8, 8 },
413 { 64, 48, 40, 48, 16, 16 },
414 { 96, 56, 48, 56, 24, 24 },
415 { 128, 64, 56, 64, 32, 32 },
416 { 160, 80, 64, 80, 40, 40 },
417 { 192, 96, 80, 96, 48, 48 },
418 { 224, 112, 96, 112, 56, 56 },
419 { 256, 128, 112, 128, 64, 64 },
420 { 288, 160, 128, 144, 80, 80 },
421 { 320, 192, 160, 160, 96, 96 },
422 { 352, 224, 192, 176, 112, 112 },
423 { 384, 256, 224, 192, 128, 128 },
424 { 416, 320, 256, 224, 144, 144 },
425 { 448, 384, 320, 256, 160, 160 },
426 { -1, -1, -1, -1, -1, -1 }
427 };
428
429 static gint freq_table[4][3] = {
430 { 44100, 22050, 11025 },
431 { 48000, 24000, 12000 },
432 { 32000, 16000, 8000 },
433 { -1, -1, -1 }
434 };
435
436 static gint spf_table[6] = {
437 48, 144, 144, 48, 144, 72
438 };
439
440 static void
441 id3tag_free (id3tag *tags)
442 {
443 g_free (tags->title);
444 g_free (tags->artist);
445 g_free (tags->album);
446 g_free (tags->recording_time);
447 g_free (tags->comment);
448 g_free (tags->genre);
449 g_free (tags->encoding);
450 }
451
452 static void
453 id3v2tag_free (id3v2tag *tags)
454 {
455 g_free (tags->album);
456 g_free (tags->comment);
457 g_free (tags->content_type);
458 g_free (tags->copyright);
459 g_free (tags->performer1);
460 g_free (tags->performer2);
461 g_free (tags->composer);
462 g_free (tags->publisher);
463 g_free (tags->recording_time);
464 g_free (tags->release_time);
465 g_free (tags->encoded_by);
466 g_free (tags->text);
467 g_free (tags->toly);
468 g_free (tags->title1);
469 g_free (tags->title2);
470 g_free (tags->title3);
471 }
472
473 static gboolean
474 guess_dlna_profile (gint bitrate,
475 gint frequency,
476 gint mpeg_version,
477 gint layer_version,
478 gint n_channels,
479 const gchar **dlna_profile,
480 const gchar **dlna_mimetype)
481 {
482 if (mpeg_version == MPEG_V1 &&
483 layer_version == LAYER_3 &&
484 (bitrate >= 32000 && bitrate <= 320000) &&
485 (n_channels == 1 || n_channels == 2) &&
486 (frequency == freq_table[0][0] ||
487 frequency == freq_table[1][0] ||
488 frequency == freq_table[2][0])) {
489 *dlna_profile = "MP3";
490 *dlna_mimetype = "audio/mpeg";
491 return TRUE;
492 }
493
494 if ((bitrate >= 8000 && bitrate <= 320000) &&
495 (mpeg_version == MPEG_V1 || mpeg_version == MPEG_V2) &&
496 (frequency == freq_table[0][0] || frequency == freq_table[0][1] ||
497 frequency == freq_table[1][0] || frequency == freq_table[1][1] ||
498 frequency == freq_table[2][0] || frequency == freq_table[2][1])) {
499 *dlna_profile = "MP3X";
500 *dlna_mimetype = "audio/mpeg";
501 return TRUE;
502 }
503
504 return FALSE;
505 }
506
507 static char *
508 read_id3v1_buffer (int fd,
509 goffset size)
510 {
511 char *buffer;
512 guint bytes_read;
513 guint rc;
514
515 if (size < 128) {
516 return NULL;
517 }
518
519 if (lseek (fd, size - ID3V1_SIZE, SEEK_SET) < 0) {
520 return NULL;
521 }
522
523 buffer = g_malloc (ID3V1_SIZE);
524
525 if (!buffer) {
526 return NULL;
527 }
528
529 bytes_read = 0;
530
531 while (bytes_read < ID3V1_SIZE) {
532 rc = read (fd,
533 buffer + bytes_read,
534 ID3V1_SIZE - bytes_read);
535 if (rc == -1) {
536 if (errno != EINTR) {
537 g_free (buffer);
538 return NULL;
539 }
540 } else if (rc == 0) {
541 break;
542 } else {
543 bytes_read += rc;
544 }
545 }
546
547 return buffer;
548 }
549
550 /* Convert from UCS-2 to UTF-8 checking the BOM.*/
551 static gchar *
552 ucs2_to_utf8(const gchar *data, guint len)
553 {
554 const gchar *encoding = NULL;
555 guint16 c;
556 gboolean be;
557 gchar *utf8 = NULL;
558
559 memcpy (&c, data, 2);
560
561 switch (c) {
562 case 0xfeff:
563 case 0xfffe:
564 be = (G_BYTE_ORDER == G_BIG_ENDIAN);
565 be = (c == 0xfeff) ? be : !be;
566 encoding = be ? "UCS-2BE" : "UCS-2LE";
567 data += 2;
568 len -= 2;
569 break;
570 default:
571 encoding = "UCS-2";
572 break;
573 }
574
575 utf8 = g_convert (data, len, "UTF-8", encoding, NULL, NULL, NULL);
576
577 return utf8;
578 }
579
580 /* Get the genre codes from regular expressions */
581 static gboolean
582 get_genre_number (const char *str, guint *genre)
583 {
584 static GRegex *regex1 = NULL;
585 static GRegex *regex2 = NULL;
586 GMatchInfo *info = NULL;
587 gchar *result = NULL;
588
589 if (!regex1) {
590 regex1 = g_regex_new ("\\(([0-9]+)\\)", 0, 0, NULL);
591 }
592
593 if (!regex2) {
594 regex2 = g_regex_new ("([0-9]+)\\z", 0, 0, NULL);
595 }
596
597 if (g_regex_match (regex1, str, 0, &info)) {
598 result = g_match_info_fetch (info, 1);
599 if (result) {
600 *genre = atoi (result);
601 g_free (result);
602 g_match_info_free (info);
603 return TRUE;
604 }
605 }
606
607 g_match_info_free (info);
608
609 if (g_regex_match (regex2, str, 0, &info)) {
610 result = g_match_info_fetch (info, 1);
611 if (result) {
612 *genre = atoi (result);
613 g_free (result);
614 g_match_info_free (info);
615 return TRUE;
616 }
617 }
618
619 g_match_info_free (info);
620
621 return FALSE;
622 }
623
624 static const gchar *
625 get_genre_name (guint number)
626 {
627 if (number >= G_N_ELEMENTS (genre_names)) {
628 return NULL;
629 }
630
631 return genre_names[number];
632 }
633
634 static void
635 un_unsync (const unsigned char *source,
636 size_t size,
637 unsigned char **destination,
638 size_t *dest_size)
639 {
640 size_t offset;
641 gchar *dest;
642 size_t new_size;
643
644 offset = 0;
645 *destination = g_malloc0 (size);
646 dest = *destination;
pointer targets in assignment differ in signedness
(emitted by gcc)
647 new_size = size;
648
649 while (offset < size) {
650 *dest = source[offset];
651
652 if ((source[offset] == 0xFF) &&
653 (source[offset + 1] == 0x00)) {
654 offset++;
655 new_size--;
656 }
657 dest++;
658 offset++;
659 }
660
661 *dest_size = new_size;
662 }
663
664 static gchar *
665 get_encoding (const gchar *data,
666 gsize size,
667 gboolean *encoding_found)
668 {
669 gchar *encoding;
670
671 /* Try to guess encoding */
672 encoding = (data && size ?
673 tracker_encoding_guess (data, size) :
674 NULL);
675
676 /* Notify if a proper detection was done */
677 if (encoding_found) {
678 *encoding_found = (encoding ? TRUE : FALSE);;
679 }
680
681 /* If no proper detection was done, return default */
682 if (!encoding) {
683 /* Use Windows-1252 instead of ISO-8859-1 as the former is a
684 superset in terms of printable characters and some
685 applications use it to encode characters in ID3 tags */
686 encoding = g_strdup ("Windows-1252");
687 }
688
689 return encoding;
690 }
691
692 static gchar *
693 convert_to_encoding (const gchar *str,
694 gssize len,
695 const gchar *to_codeset,
696 const gchar *from_codeset,
697 gsize *bytes_read,
698 gsize *bytes_written,
699 GError **error_out)
700 {
701 GError *error = NULL;
702 gchar *word;
703
704 /* g_print ("%s for %s\n", from_codeset, str); */
705
706 word = g_convert (str,
707 len,
708 to_codeset,
709 from_codeset,
710 bytes_read,
711 bytes_written,
712 &error);
713
714 if (error) {
715 gchar *encoding;
716
717 encoding = get_encoding (str, len, NULL);
718 g_free (word);
719
720 word = g_convert (str,
721 len,
722 to_codeset,
723 encoding,
724 bytes_read,
725 bytes_written,
726 error_out);
727
728 g_free (encoding);
729 g_error_free (error);
730 }
731
732 return word;
733 }
734
735 static gboolean
736 get_id3 (const gchar *data,
737 size_t size,
738 id3tag *id3)
739 {
740 gchar *encoding, *year;
741 const gchar *pos;
742
743 if (!data) {
744 return FALSE;
745 }
746
747 if (size < 128) {
748 return FALSE;
749 }
750
751 pos = &data[size - 128];
752
753 if (strncmp ("TAG", pos, 3) != 0) {
754 return FALSE;
755 }
756
757 /* Now convert all the data separately */
758 pos += 3;
759
760 /* We don't use our magic convert_to_encoding here because we
761 * have a better way to collect a bit more data before we let
762 * enca loose on it for v1.
763 */
764 if (tracker_encoding_can_guess ()) {
765 GString *s;
766 gboolean encoding_was_found;
767
768 /* Get the encoding for ALL the data we are extracting here */
769 /* This wont work with encodings where a NUL byte may be actually valid,
770 * like UTF-16 */
771 s = g_string_new_len (pos, strnlen (pos, 30));
772 g_string_append_len (s, pos + 30, strnlen (pos+30, 30));
773 g_string_append_len (s, pos + 60, strnlen (pos+60, 30));
774 g_string_append_len (s, pos + 94, strnlen (pos+94, ((pos+94)[28] != 0) ? 30 : 28));
775
776 encoding = get_encoding (s->str, s->len, &encoding_was_found);
777
778 if (encoding_was_found) {
779 id3->encoding = g_strdup (encoding);
780 }
781
782 g_string_free (s, TRUE);
783 } else {
784 /* If we cannot guess encoding, don't even try it, just
785 * use the default one */
786 encoding = get_encoding (NULL, 0, NULL);
787 }
788
789 id3->title = g_convert (pos, 30, "UTF-8", encoding, NULL, NULL, NULL);
790
791 pos += 30;
792 id3->artist = g_convert (pos, 30, "UTF-8", encoding, NULL, NULL, NULL);
793
794 pos += 30;
795 id3->album = g_convert (pos, 30, "UTF-8", encoding, NULL, NULL, NULL);
796
797 pos += 30;
798 year = g_convert (pos, 4, "UTF-8", encoding, NULL, NULL, NULL);
799 if (year && atoi (year) > 0) {
800 id3->recording_time = tracker_date_guess (year);
801 }
802 g_free (year);
803
804 pos += 4;
805
806 if (pos[28] != 0) {
807 id3->comment = g_convert (pos, 30, "UTF-8", encoding, NULL, NULL, NULL);
808 id3->track_number = 0;
809 } else {
810 gchar buf[5];
811
812 id3->comment = g_convert (pos, 28, "UTF-8", encoding, NULL, NULL, NULL);
813
814 snprintf (buf, 5, "%d", pos[29]);
815 id3->track_number = atoi (buf);
816 }
817
818 pos += 30;
819 id3->genre = g_strdup (get_genre_name ((guint) pos[0]));
820
821 if (!id3->genre) {
822 id3->genre = g_strdup ("");
823 }
824
825 g_free (encoding);
826
827 return TRUE;
828 }
829
830 /*
831 * For the MP3 frame header description, see
832 * http://www.mp3-tech.org/programmer/frame_header.html
833 */
834 static gboolean
835 mp3_parse_header (const gchar *data,
836 size_t size,
837 size_t seek_pos,
838 const gchar *uri,
839 TrackerSparqlBuilder *metadata,
840 MP3Data *filedata)
841 {
842 const gchar *dlna_profile, *dlna_mimetype;
843 guint header;
844 gchar mpeg_ver = 0;
845 gchar layer_ver = 0;
846 gint spfp8 = 0;
847 guint padsize = 0;
848 gint idx_num = 0;
849 gint bitrate = 0;
850 guint avg_bps = 0;
851 gint vbr_flag = 0;
852 guint length = 0;
853 gint sample_rate = 0;
854 guint frame_size;
855 guint frames = 0;
856 size_t pos = 0;
857 gint n_channels;
858
859 pos = seek_pos;
860
861 memcpy (&header, &data[pos], sizeof (header));
862
863 switch (header & mpeg_ver_mask) {
864 case 0x1000:
865 mpeg_ver = MPEG_V2;
866 break;
867 case 0x1800:
868 mpeg_ver = MPEG_V1;
869 break;
870 case 0:
871 mpeg_ver = MPEG_V25;
872 break;
873 default:
874 /* unknown version */
875 return FALSE;
876 }
877
878 switch (header & mpeg_layer_mask) {
879 case 0x400:
880 layer_ver = LAYER_2;
881 padsize = 1;
882 break;
883 case 0x200:
884 layer_ver = LAYER_3;
885 padsize = 1;
886 break;
887 case 0x600:
888 layer_ver = LAYER_1;
889 padsize = 4;
890 break;
891 default:
892 /* unknown layer */
893 return FALSE;
894 }
895
896 if (mpeg_ver < 3) {
897 idx_num = (mpeg_ver - 1) * 3 + layer_ver - 1;
898 } else {
899 idx_num = 2 + layer_ver;
900 }
901
902 spfp8 = spf_table[idx_num];
903
904 /* We assume mpeg version, layer and channels are constant in frames */
905 do {
906 frames++;
907
908 bitrate = 1000 * bitrate_table[(header & bitrate_mask) >> 20][idx_num];
909
910 /* Skip frame headers with bitrate index '0000' (free) or '1111' (bad) */
911 if (bitrate <= 0) {
912 frames--;
913 return FALSE;
914 }
915
916 sample_rate = freq_table[(header & freq_mask) >> 18][mpeg_ver - 1];
917
918 /* Skip frame headers with frequency index '11' (reserved) */
919 if (sample_rate <= 0) {
920 frames--;
921 return FALSE;
922 }
923
924 frame_size = spfp8 * bitrate / sample_rate + padsize*((header & pad_mask) >> 17);
925 avg_bps += bitrate / 1000;
926
927 pos += frame_size;
928
929 if (frames > MAX_FRAMES_SCAN) {
930 /* Optimization */
931 break;
932 }
933
934 if (avg_bps / frames != bitrate / 1000) {
935 vbr_flag = 1;
936 }
937
938 if (pos + sizeof (header) > size) {
939 /* EOF */
940 break;
941 }
942
943 if ((!vbr_flag) && (frames > VBR_THRESHOLD)) {
944 break;
945 }
946
947 memcpy(&header, &data[pos], sizeof (header));
948 } while ((header & sync_mask) == sync_mask);
949
950 /* At least 2 frames to check the right position */
951 if (frames < 2) {
952 /* No valid frames */
953 return FALSE;
954 }
955
956 tracker_sparql_builder_predicate (metadata, "nfo:codec");
957 tracker_sparql_builder_object_string (metadata, "MPEG");
958
959 n_channels = ((header & ch_mask) == ch_mask) ? 1 : 2;
960
961 tracker_sparql_builder_predicate (metadata, "nfo:channels");
962 tracker_sparql_builder_object_int64 (metadata, n_channels);
963
964 avg_bps /= frames;
965
966 if ((!vbr_flag && frames > VBR_THRESHOLD) || (frames > MAX_FRAMES_SCAN)) {
967 /* If not all frames scanned
968 * Note that bitrate is always > 0, checked before */
969 length = (filedata->size - filedata->id3v2_size) / (avg_bps ? avg_bps : bitrate) / 125;
970 } else {
971 /* Note that sample_rate is always > 0, checked before */
972 length = spfp8 * 8 * frames / sample_rate;
973 }
974
975 tracker_sparql_builder_predicate (metadata, "nfo:duration");
976 tracker_sparql_builder_object_int64 (metadata, length);
977
978 tracker_sparql_builder_predicate (metadata, "nfo:sampleRate");
979 tracker_sparql_builder_object_int64 (metadata, sample_rate);
980 tracker_sparql_builder_predicate (metadata, "nfo:averageBitrate");
981 tracker_sparql_builder_object_int64 (metadata, avg_bps*1000);
982
983 if (guess_dlna_profile (bitrate, sample_rate,
984 mpeg_ver, layer_ver, n_channels,
985 &dlna_profile, &dlna_mimetype)) {
986 tracker_sparql_builder_predicate (metadata, "nmm:dlnaProfile");
987 tracker_sparql_builder_object_string (metadata, dlna_profile);
988 tracker_sparql_builder_predicate (metadata, "nmm:dlnaMime");
989 tracker_sparql_builder_object_string (metadata, dlna_mimetype);
990 }
991
992 return TRUE;
993 }
994
995 static void
996 mp3_parse (const gchar *data,
997 size_t size,
998 size_t offset,
999 const gchar *uri,
1000 TrackerSparqlBuilder *metadata,
1001 MP3Data *filedata)
1002 {
1003 guint header;
1004 guint counter = 0;
1005 guint pos = offset;
1006
1007 do {
1008 /* Seek for frame start */
1009 if (pos + sizeof (header) > size) {
1010 return;
1011 }
1012
1013 memcpy (&header, &data[pos], sizeof (header));
1014
1015 if ((header & sync_mask) == sync_mask) {
1016 /* Found header sync */
1017 if (mp3_parse_header (data, size, pos, uri, metadata, filedata)) {
1018 return;
1019 }
1020 }
1021
1022 pos++;
1023 counter++;
1024 } while (counter < MAX_MP3_SCAN_DEEP);
1025 }
1026
1027 static gssize
1028 id3v2_nul_size (const gchar encoding)
1029 {
1030 switch (encoding) {
1031 case 0x01:
1032 case 0x02:
1033 /* UTF-16, string terminated by two NUL bytes */
1034 return 2;
1035 default:
1036 return 1;
1037 }
1038 }
1039
1040 static gssize
1041 id3v2_strlen (const gchar encoding,
1042 const gchar *text,
1043 gssize len)
1044 {
1045 const gchar *pos;
1046
1047 switch (encoding) {
1048 case 0x01:
1049 case 0x02:
1050
1051 /* UTF-16, string terminated by two NUL bytes */
1052 pos = memmem (text, len, "\0\0\0", 3);
1053
1054 if (pos == NULL) {
1055 pos = memmem (text, len, "\0\0", 2);
1056 } else {
1057 pos++;
1058 }
1059
1060 if (pos != NULL) {
1061 return pos - text;
1062 } else {
1063 return len;
1064 }
1065 default:
1066 return strnlen (text, len);
1067 }
1068 }
1069
1070 static gchar *
1071 id3v24_text_to_utf8 (const gchar encoding,
1072 const gchar *text,
1073 gssize len,
1074 id3tag *info)
1075 {
1076 /* This byte describes the encoding
1077 * try to convert strings to UTF-8
1078 * if it fails, then forget it.
1079 * For UTF-16 if size odd assume invalid 00 term.
1080 */
1081
1082 switch (encoding) {
1083 case 0x00:
1084 /* Use Windows-1252 instead of ISO-8859-1 as the former is a
1085 superset in terms of printable characters and some
1086 applications use it to encode characters in ID3 tags */
1087 return convert_to_encoding (text,
1088 len,
1089 "UTF-8",
1090 info->encoding ? info->encoding : "Windows-1252",
1091 NULL, NULL, NULL);
1092 case 0x01 :
1093 return convert_to_encoding (text,
1094 len - len%2,
1095 "UTF-8",
1096 "UTF-16",
1097 NULL, NULL, NULL);
1098 case 0x02 :
1099 return convert_to_encoding (text,
1100 len - len%2,
1101 "UTF-8",
1102 "UTF-16BE",
1103 NULL, NULL, NULL);
1104 case 0x03 :
1105 return strndup (text, len);
1106
1107 default:
1108 /* Bad encoding byte,
1109 * try to convert from
1110 * Windows-1252
1111 */
1112 return convert_to_encoding (text,
1113 len,
1114 "UTF-8",
1115 info->encoding ? info->encoding : "Windows-1252",
1116 NULL, NULL, NULL);
1117 }
1118 }
1119
1120 static gchar *
1121 id3v2_text_to_utf8 (const gchar encoding,
1122 const gchar *text,
1123 gssize len,
1124 id3tag *info)
1125 {
1126 /* This byte describes the encoding
1127 * try to convert strings to UTF-8
1128 * if it fails, then forget it
1129 * For UCS2 if size odd assume invalid 00 term.
1130 */
1131
1132 switch (encoding) {
1133 case 0x00:
1134 /* Use Windows-1252 instead of ISO-8859-1 as the former is a
1135 superset in terms of printable characters and some
1136 applications use it to encode characters in ID3 tags */
1137 return convert_to_encoding (text,
1138 len,
1139 "UTF-8",
1140 info->encoding ? info->encoding : "Windows-1252",
1141 NULL, NULL, NULL);
1142 case 0x01 :
1143 /* return g_convert (text, */
1144 /* len, */
1145 /* "UTF-8", */
1146 /* "UCS-2", */
1147 /* NULL, NULL, NULL); */
1148 return ucs2_to_utf8 (text, len - len%2);
1149
1150 default:
1151 /* Bad encoding byte,
1152 * try to convert from
1153 * Windows-1252
1154 */
1155 return convert_to_encoding (text,
1156 len,
1157 "UTF-8",
1158 info->encoding ? info->encoding : "Windows-1252",
1159 NULL, NULL, NULL);
1160 }
1161 }
1162
1163 static id3v24frame
1164 id3v24_get_frame (const gchar *name)
1165 {
1166 gint l, r, m;
1167
1168 /* use binary search */
1169
1170 l = 0;
1171 r = G_N_ELEMENTS (id3v24_frames) - 1;
1172 m = 0;
1173
1174 do {
1175 m = (l + r) / 2;
1176 if (strncmp (name, id3v24_frames[m].name, 4) < 0) {
1177 /* left half */
1178 r = m - 1;
1179 } else {
1180 /* right half */
1181 l = m + 1;
1182 }
1183 } while (l <= r && strncmp (id3v24_frames[m].name, name, 4) != 0);
1184
1185 if (strncmp (id3v24_frames[m].name, name, 4) == 0) {
1186 return id3v24_frames[m].frame;
1187 } else {
1188 return ID3V24_UNKNOWN;
1189 }
1190 }
1191
1192 static id3v2frame
1193 id3v2_get_frame (const gchar *name)
1194 {
1195 gint l, r, m;
1196
1197 /* use binary search */
1198
1199 l = 0;
1200 r = G_N_ELEMENTS (id3v2_frames) - 1;
1201 m = 0;
1202
1203 do {
1204 m = (l + r) / 2;
1205 if (strncmp (name, id3v2_frames[m].name, 3) < 0) {
1206 /* left half */
1207 r = m - 1;
1208 } else {
1209 /* right half */
1210 l = m + 1;
1211 }
1212 } while (l <= r && strncmp (id3v2_frames[m].name, name, 3) != 0);
1213
1214 if (strncmp (id3v2_frames[m].name, name, 3) == 0) {
1215 return id3v2_frames[m].frame;
1216 } else {
1217 return ID3V2_UNKNOWN;
1218 }
1219 }
1220
1221 static void
1222 get_id3v24_tags (id3v24frame frame,
1223 const gchar *data,
1224 size_t csize,
1225 id3tag *info,
1226 const gchar *uri,
1227 TrackerSparqlBuilder *metadata,
1228 MP3Data *filedata)
1229 {
1230 id3v2tag *tag = &filedata->id3v24;
1231 guint pos = 0;
1232
1233 switch (frame) {
1234 case ID3V24_APIC: {
1235 /* embedded image */
1236 gchar text_type;
1237 const gchar *mime;
1238 gchar pic_type;
1239 const gchar *desc;
1240 guint offset;
1241 gint mime_len;
1242
1243 text_type = data[pos + 0];
1244 mime = &data[pos + 1];
1245 mime_len = strnlen (mime, csize - 1);
1246 pic_type = data[pos + 1 + mime_len + 1];
1247 desc = &data[pos + 1 + mime_len + 1 + 1];
1248
1249 if (pic_type == 3 || (pic_type == 0 && filedata->media_art_size == 0)) {
1250 offset = pos + 1 + mime_len + 2;
1251 offset += id3v2_strlen (text_type, desc, csize - offset) + id3v2_nul_size (text_type);
1252
1253 filedata->media_art_data = g_malloc0 (csize - offset);
1254 filedata->media_art_mime = g_strndup (mime, mime_len);
1255 memcpy (filedata->media_art_data, &data[offset], csize - offset);
1256 filedata->media_art_size = csize - offset;
1257 }
1258 break;
1259 }
1260
1261 case ID3V24_COMM: {
1262 gchar *word;
1263 gchar text_encode;
1264 const gchar *text_desc;
1265 const gchar *text;
1266 guint offset;
1267 gint text_desc_len;
1268
1269 text_encode = data[pos + 0]; /* $xx */
1270 text_desc = &data[pos + 4]; /* <text string according to encoding> $00 (00) */
1271 text_desc_len = id3v2_strlen (text_encode, text_desc, csize - 4);
1272
1273 offset = 4 + text_desc_len + id3v2_nul_size (text_encode);
1274 text = &data[pos + offset]; /* <full text string according to encoding> */
1275
1276 word = id3v24_text_to_utf8 (text_encode, text, csize - offset, info);
1277
1278 if (!tracker_is_empty_string (word)) {
1279 g_strstrip (word);
1280 g_free (tag->comment);
1281 tag->comment = word;
1282 } else {
1283 g_free (word);
1284 }
1285 break;
1286 }
1287
1288 default: {
1289 gchar *word;
1290
1291 /* text frames */
1292 word = id3v24_text_to_utf8 (data[pos], &data[pos + 1], csize - 1, info);
1293 if (!tracker_is_empty_string (word)) {
1294 g_strstrip (word);
1295 } else {
1296 /* Can't do anything without word. */
1297 break;
1298 }
1299
1300 #ifdef FRAME_ENABLE_TRACE
1301 g_debug ("ID3v2.4: Frame is %d, word is %s", frame, word);
1302 #endif /* FRAME_ENABLE_TRACE */
1303
1304 switch (frame) {
1305 case ID3V24_TALB:
1306 tag->album = word;
1307 break;
1308 case ID3V24_TCON: {
1309 gint genre;
1310
1311 if (get_genre_number (word, &genre)) {
pointer targets in passing argument 2 of 'get_genre_number' differ in signedness
(emitted by gcc)
1312 g_free (word);
1313 word = g_strdup (get_genre_name (genre));
1314 }
1315 if (word && strcasecmp (word, "unknown") != 0) {
1316 tag->content_type = word;
1317 } else {
1318 g_free (word);
1319 }
1320 break;
1321 }
1322 case ID3V24_TCOP:
1323 tag->copyright = word;
1324 break;
1325 case ID3V24_TDRC:
1326 tag->recording_time = tracker_date_guess (word);
1327 g_free (word);
1328 break;
1329 case ID3V24_TDRL:
1330 tag->release_time = tracker_date_guess (word);
1331 g_free (word);
1332 break;
1333 case ID3V24_TENC:
1334 tag->encoded_by = word;
1335 break;
1336 case ID3V24_TEXT:
1337 tag->text = word;
1338 break;
1339 case ID3V24_TOLY:
1340 tag->toly = word;
1341 break;
1342 case ID3V24_TCOM:
1343 tag->composer = word;
1344 break;
1345 case ID3V24_TIT1:
1346 tag->title1 = word;
1347 break;
1348 case ID3V24_TIT2:
1349 tag->title2 = word;
1350 break;
1351 case ID3V24_TIT3:
1352 tag->title3 = word;
1353 break;
1354 case ID3V24_TLEN:
1355 tag->length = atoi (word) / 1000;
1356 g_free (word);
1357 break;
1358 case ID3V24_TPE1:
1359 tag->performer1 = word;
1360 break;
1361 case ID3V24_TPE2:
1362 tag->performer2 = word;
1363 break;
1364 case ID3V24_TPUB:
1365 tag->publisher = word;
1366 break;
1367 case ID3V24_TRCK: {
1368 gchar **parts;
1369
1370 parts = g_strsplit (word, "/", 2);
1371 if (parts[0]) {
1372 tag->track_number = atoi (parts[0]);
1373 if (parts[1]) {
1374 tag->track_count = atoi (parts[1]);
1375 }
1376 }
1377 g_strfreev (parts);
1378 g_free (word);
1379
1380 break;
1381 }
1382 case ID3V24_TPOS: {
1383 gchar **parts;
1384
1385 parts = g_strsplit (word, "/", 2);
1386 if (parts[0]) {
1387 tag->set_number = atoi (parts[0]);
1388 if (parts[1]) {
1389 tag->set_count = atoi (parts[1]);
1390 }
1391 }
1392 g_strfreev (parts);
1393 g_free (word);
1394
1395 break;
1396 }
1397 case ID3V24_TYER:
1398 if (atoi (word) > 0) {
1399 tag->recording_time = tracker_date_guess (word);
1400 }
1401 g_free (word);
1402 break;
1403 default:
1404 g_free (word);
1405 }
1406 }
1407 }
1408 }
1409
1410 static void
1411 get_id3v23_tags (id3v24frame frame,
1412 const gchar *data,
1413 size_t csize,
1414 id3tag *info,
1415 const gchar *uri,
1416 TrackerSparqlBuilder *metadata,
1417 MP3Data *filedata)
1418 {
1419 id3v2tag *tag = &filedata->id3v23;
1420 guint pos = 0;
1421
1422 switch (frame) {
1423 case ID3V24_APIC: {
1424 /* embedded image */
1425 gchar text_type;
1426 const gchar *mime;
1427 gchar pic_type;
1428 const gchar *desc;
1429 guint offset;
1430 gint mime_len;
1431
1432 text_type = data[pos + 0];
1433 mime = &data[pos + 1];
1434 mime_len = strnlen (mime, csize - 1);
1435 pic_type = data[pos + 1 + mime_len + 1];
1436 desc = &data[pos + 1 + mime_len + 1 + 1];
1437
1438 if (pic_type == 3 || (pic_type == 0 && filedata->media_art_size == 0)) {
1439 offset = pos + 1 + mime_len + 2;
1440 offset += id3v2_strlen (text_type, desc, csize - offset) + id3v2_nul_size (text_type);
1441
1442 filedata->media_art_data = g_malloc0 (csize - offset);
1443 filedata->media_art_mime = g_strndup (mime, mime_len);
1444 memcpy (filedata->media_art_data, &data[offset], csize - offset);
1445 filedata->media_art_size = csize - offset;
1446 }
1447 break;
1448 }
1449
1450 case ID3V24_COMM: {
1451 gchar *word;
1452 gchar text_encode;
1453 const gchar *text_desc;
1454 const gchar *text;
1455 guint offset;
1456 gint text_desc_len;
1457
1458 text_encode = data[pos + 0]; /* $xx */
1459 text_desc = &data[pos + 4]; /* <text string according to encoding> $00 (00) */
1460 text_desc_len = id3v2_strlen (text_encode, text_desc, csize - 4);
1461
1462 offset = 4 + text_desc_len + id3v2_nul_size (text_encode);
1463 text = &data[pos + offset]; /* <full text string according to encoding> */
1464
1465 word = id3v2_text_to_utf8 (text_encode, text, csize - offset, info);
1466
1467 if (!tracker_is_empty_string (word)) {
1468 g_strstrip (word);
1469 g_free (tag->comment);
1470 tag->comment = word;
1471 } else {
1472 g_free (word);
1473 }
1474
1475 break;
1476 }
1477
1478 default: {
1479 gchar *word;
1480
1481 /* text frames */
1482 word = id3v2_text_to_utf8 (data[pos], &data[pos + 1], csize - 1, info);
1483
1484 if (!tracker_is_empty_string (word)) {
1485 g_strstrip (word);
1486 } else {
1487 /* Can't do anything without word. */
1488 break;
1489 }
1490
1491
1492 #ifdef FRAME_ENABLE_TRACE
1493 g_debug ("ID3v2.3: Frame is %d, word is %s", frame, word);
1494 #endif /* FRAME_ENABLE_TRACE */
1495
1496 switch (frame) {
1497 case ID3V24_TALB:
1498 tag->album = word;
1499 break;
1500 case ID3V24_TCON: {
1501 gint genre;
1502
1503 if (get_genre_number (word, &genre)) {
pointer targets in passing argument 2 of 'get_genre_number' differ in signedness
(emitted by gcc)
1504 g_free (word);
1505 word = g_strdup (get_genre_name (genre));
1506 }
1507 if (word && strcasecmp (word, "unknown") != 0) {
1508 tag->content_type = word;
1509 } else {
1510 g_free (word);
1511 }
1512 break;
1513 }
1514 case ID3V24_TCOP:
1515 tag->copyright = word;
1516 break;
1517 case ID3V24_TENC:
1518 tag->encoded_by = word;
1519 break;
1520 case ID3V24_TEXT:
1521 tag->text = word;
1522 break;
1523 case ID3V24_TOLY:
1524 tag->toly = word;
1525 break;
1526 case ID3V24_TCOM:
1527 tag->composer = word;
1528 break;
1529 case ID3V24_TIT1:
1530 tag->title1 = word;
1531 break;
1532 case ID3V24_TIT2:
1533 tag->title2 = word;
1534 break;
1535 case ID3V24_TIT3:
1536 tag->title3 = word;
1537 break;
1538 case ID3V24_TLEN:
1539 tag->length = atoi (word) / 1000;
1540 g_free (word);
1541 break;
1542 case ID3V24_TPE1:
1543 tag->performer1 = word;
1544 break;
1545 case ID3V24_TPE2:
1546 tag->performer2 = word;
1547 break;
1548 case ID3V24_TPUB:
1549 tag->publisher = word;
1550 break;
1551 case ID3V24_TRCK: {
1552 gchar **parts;
1553
1554 parts = g_strsplit (word, "/", 2);
1555 if (parts[0]) {
1556 tag->track_number = atoi (parts[0]);
1557 if (parts[1]) {
1558 tag->track_count = atoi (parts[1]);
1559 }
1560 }
1561 g_strfreev (parts);
1562 g_free (word);
1563
1564 break;
1565 }
1566 case ID3V24_TPOS: {
1567 gchar **parts;
1568
1569 parts = g_strsplit (word, "/", 2);
1570 if (parts[0]) {
1571 tag->set_number = atoi (parts[0]);
1572 if (parts[1]) {
1573 tag->set_count = atoi (parts[1]);
1574 }
1575 }
1576 g_strfreev (parts);
1577 g_free (word);
1578
1579 break;
1580 }
1581 case ID3V24_TYER:
1582 if (atoi (word) > 0) {
1583 tag->recording_time = tracker_date_guess (word);
1584 }
1585 g_free (word);
1586 break;
1587 default:
1588 g_free (word);
1589 }
1590 }
1591 }
1592 }
1593
1594 static void
1595 get_id3v20_tags (id3v2frame frame,
1596 const gchar *data,
1597 size_t csize,
1598 id3tag *info,
1599 const gchar *uri,
1600 TrackerSparqlBuilder *metadata,
1601 MP3Data *filedata)
1602 {
1603 id3v2tag *tag = &filedata->id3v22;
1604 guint pos = 0;
1605
1606 if (frame == ID3V2_PIC) {
1607 /* embedded image */
1608 gchar text_type;
1609 gchar pic_type;
1610 const gchar *desc;
1611 guint offset;
1612 const gchar *mime;
1613
1614 text_type = data[pos + 0];
1615 mime = &data[pos + 1];
1616 pic_type = data[pos + 1 + 3];
1617 desc = &data[pos + 1 + 3 + 1];
1618
1619 if (pic_type == 3 || (pic_type == 0 && filedata->media_art_size == 0)) {
1620 offset = pos + 1 + 3 + 1;
1621 offset += id3v2_strlen (text_type, desc, csize - offset) + id3v2_nul_size (text_type);
1622
1623 filedata->media_art_mime = g_strndup (mime, 3);
1624 filedata->media_art_data = g_malloc0 (csize - offset);
1625 memcpy (filedata->media_art_data, &data[offset], csize - offset);
1626 filedata->media_art_size = csize - offset;
1627 }
1628 } else {
1629 /* text frames */
1630 gchar *word;
1631
1632 word = id3v2_text_to_utf8 (data[pos], &data[pos + 1], csize - 1, info);
1633 if (!tracker_is_empty_string (word)) {
1634 g_strstrip (word);
1635 } else {
1636 /* Can't do anything without word. */
1637 return;
1638 }
1639
1640 #ifdef FRAME_ENABLE_TRACE
1641 g_debug ("ID3v2.2: Frame is %d, word is %s", frame, word);
1642 #endif /* FRAME_ENABLE_TRACE */
1643
1644 switch (frame) {
1645 case ID3V2_COM:
1646 tag->comment = word;
1647 break;
1648 case ID3V2_TAL:
1649 tag->album = word;
1650 break;
1651 case ID3V2_TCO: {
1652 gint genre;
1653
1654 if (get_genre_number (word, &genre)) {
pointer targets in passing argument 2 of 'get_genre_number' differ in signedness
(emitted by gcc)
1655 g_free (word);
1656 word = g_strdup (get_genre_name (genre));
1657 }
1658
1659 if (word && strcasecmp (word, "unknown") != 0) {
1660 tag->content_type = word;
1661 } else {
1662 g_free (word);
1663 }
1664
1665 break;
1666 }
1667 case ID3V2_TCR:
1668 tag->copyright = word;
1669 break;
1670 case ID3V2_TEN:
1671 tag->encoded_by = word;
1672 break;
1673 case ID3V2_TLE:
1674 tag->length = atoi (word) / 1000;
1675 g_free (word);
1676 break;
1677 case ID3V2_TPB:
1678 tag->publisher = word;
1679 break;
1680 case ID3V2_TP1:
1681 tag->performer1 = word;
1682 break;
1683 case ID3V2_TP2:
1684 tag->performer2 = word;
1685 break;
1686 case ID3V2_TRK: {
1687 gchar **parts;
1688
1689 parts = g_strsplit (word, "/", 2);
1690 if (parts[0]) {
1691 tag->track_number = atoi (parts[0]);
1692 if (parts[1]) {
1693 tag->track_count = atoi (parts[1]);
1694 }
1695 }
1696 g_strfreev (parts);
1697 g_free (word);
1698
1699 break;
1700 }
1701 case ID3V2_TT1:
1702 tag->title1 = word;
1703 break;
1704 case ID3V2_TT2:
1705 tag->title2 = word;
1706 break;
1707 case ID3V2_TT3:
1708 tag->title3 = word;
1709 break;
1710 case ID3V2_TXT:
1711 tag->text = word;
1712 break;
1713 case ID3V2_TYE:
1714 if (atoi (word) > 0) {
1715 tag->recording_time = tracker_date_guess (word);
1716 }
1717 g_free (word);
1718 break;
1719 default:
1720 g_free (word);
1721 }
1722 }
1723 }
1724
1725 static void
1726 parse_id3v24 (const gchar *data,
1727 size_t size,
1728 id3tag *info,
1729 const gchar *uri,
1730 TrackerSparqlBuilder *metadata,
1731 MP3Data *filedata,
1732 size_t *offset_delta)
1733 {
1734 gint unsync;
1735 gint ext_header;
1736 gint experimental;
1737 guint tsize;
1738 guint pos;
1739 guint ext_header_size;
1740
1741 if ((size < 16) ||
1742 (data[0] != 0x49) ||
1743 (data[1] != 0x44) ||
1744 (data[2] != 0x33) ||
1745 (data[3] != 0x04) ||
1746 (data[4] != 0x00) ) {
1747 return;
1748 }
1749
1750 unsync = (data[5] & 0x80) > 0;
1751 ext_header = (data[5] & 0x40) > 0;
1752 experimental = (data[5] & 0x20) > 0;
1753 tsize = (((data[6] & 0x7F) << 21) |
1754 ((data[7] & 0x7F) << 14) |
1755 ((data[8] & 0x7F) << 7) |
1756 ((data[9] & 0x7F) << 0));
1757
1758 if ((tsize + 10 > size) || (experimental)) {
1759 return;
1760 }
1761
1762 pos = 10;
1763
1764 if (ext_header) {
1765 ext_header_size = (((data[10] & 0x7F) << 21) |
1766 ((data[11] & 0x7F) << 14) |
1767 ((data[12] & 0x7F) << 7) |
1768 ((data[13] & 0x7F) << 0));
1769 pos += ext_header_size;
1770
1771 if (pos + tsize > size) {
1772 /* invalid size: extended header longer than tag */
1773 return;
1774 }
1775 }
1776
1777 while (pos < size) {
1778 id3v24frame frame;
1779 size_t csize;
1780 unsigned short flags;
1781
1782 if (pos + 10 > size) {
1783 return;
1784 }
1785
1786 frame = id3v24_get_frame (&data[pos]);
1787
1788 csize = (((data[pos+4] & 0x7F) << 21) |
1789 ((data[pos+5] & 0x7F) << 14) |
1790 ((data[pos+6] & 0x7F) << 7) |
1791 ((data[pos+7] & 0x7F) << 0));
1792
1793 flags = (((unsigned char) (data[pos + 8]) << 8) +
1794 ((unsigned char) (data[pos + 9])));
1795
1796 pos += 10;
1797
1798 if (frame == ID3V24_UNKNOWN) {
1799 /* ignore unknown frames */
1800 pos += csize;
1801 continue;
1802 }
1803
1804 if (pos + csize > size) {
1805 break;
1806 } else if (csize == 0) {
1807 continue;
1808 }
1809
1810 if (((flags & 0x80) > 0) ||
1811 ((flags & 0x40) > 0)) {
1812 pos += csize;
1813 continue;
1814 }
1815
1816 if ((flags & 0x20) > 0) {
1817 /* The "group" identifier, skip a byte */
1818 pos++;
1819 csize--;
1820 }
1821
1822 if ((flags & 0x02) || unsync) {
1823 size_t unsync_size;
1824 gchar *body;
1825
1826 un_unsync (&data[pos], csize, (unsigned char **) &body, &unsync_size);
pointer targets in passing argument 1 of 'un_unsync' differ in signedness
(emitted by gcc)
1827 get_id3v24_tags (frame, body, unsync_size, info, uri, metadata, filedata);
1828 g_free (body);
1829 } else {
1830 get_id3v24_tags (frame, &data[pos], csize, info, uri, metadata, filedata);
1831 }
1832
1833 pos += csize;
1834 }
1835
1836 *offset_delta = tsize + 10;
1837 }
1838
1839 static void
1840 parse_id3v23 (const gchar *data,
1841 size_t size,
1842 id3tag *info,
1843 const gchar *uri,
1844 TrackerSparqlBuilder *metadata,
1845 MP3Data *filedata,
1846 size_t *offset_delta)
1847 {
1848 gint unsync;
1849 gint ext_header;
1850 gint experimental;
1851 guint tsize;
1852 guint pos;
1853 guint ext_header_size;
1854 guint padding;
1855
1856 if ((size < 16) ||
1857 (data[0] != 0x49) ||
1858 (data[1] != 0x44) ||
1859 (data[2] != 0x33) ||
1860 (data[3] != 0x03) ||
1861 (data[4] != 0x00)) {
1862 return;
1863 }
1864
1865 unsync = (data[5] & 0x80) > 0;
1866 ext_header = (data[5] & 0x40) > 0;
1867 experimental = (data[5] & 0x20) > 0;
1868 tsize = (((data[6] & 0x7F) << 21) |
1869 ((data[7] & 0x7F) << 14) |
1870 ((data[8] & 0x7F) << 7) |
1871 ((data[9] & 0x7F) << 0));
1872
1873 if ((tsize + 10 > size) || (experimental)) {
1874 return;
1875 }
1876
1877 pos = 10;
1878 padding = 0;
1879
1880 if (ext_header) {
1881 ext_header_size = (((unsigned char)(data[10]) << 24) |
1882 ((unsigned char)(data[11]) << 16) |
1883 ((unsigned char)(data[12]) << 8) |
1884 ((unsigned char)(data[12]) << 0));
1885
1886 padding = (((unsigned char)(data[15]) << 24) |
1887 ((unsigned char)(data[16]) << 16) |
1888 ((unsigned char)(data[17]) << 8) |
1889 ((unsigned char)(data[18]) << 0));
1890
1891 pos += 4 + ext_header_size;
1892
1893 if (padding < tsize)
1894 tsize -= padding;
1895 else {
1896 return;
1897 }
1898
1899 if (pos + tsize > size) {
1900 /* invalid size: extended header longer than tag */
1901 return;
1902 }
1903 }
1904
1905 while (pos < size) {
1906 id3v24frame frame;
1907 size_t csize;
1908 unsigned short flags;
1909
1910 if (pos + 10 > size) {
1911 return;
1912 }
1913
1914 frame = id3v24_get_frame (&data[pos]);
1915
1916 csize = (((unsigned char)(data[pos + 4]) << 24) |
1917 ((unsigned char)(data[pos + 5]) << 16) |
1918 ((unsigned char)(data[pos + 6]) << 8) |
1919 ((unsigned char)(data[pos + 7]) << 0) );
1920
1921 flags = (((unsigned char)(data[pos + 8]) << 8) +
1922 ((unsigned char)(data[pos + 9])));
1923
1924 pos += 10;
1925
1926 if (frame == ID3V24_UNKNOWN) {
1927 /* ignore unknown frames */
1928 pos += csize;
1929 continue;
1930 }
1931
1932 if (pos + csize > size) {
1933 break;
1934 } else if (csize == 0) {
1935 continue;
1936 }
1937
1938 if (((flags & 0x80) > 0) || ((flags & 0x40) > 0)) {
1939 pos += csize;
1940 continue;
1941 }
1942
1943 if ((flags & 0x20) > 0) {
1944 /* The "group" identifier, skip a byte */
1945 pos++;
1946 csize--;
1947 }
1948
1949 if ((flags & 0x02) || unsync) {
1950 size_t unsync_size;
1951 gchar *body;
1952
1953 un_unsync (&data[pos], csize, (unsigned char **) &body, &unsync_size);
pointer targets in passing argument 1 of 'un_unsync' differ in signedness
(emitted by gcc)
1954 get_id3v23_tags (frame, body, unsync_size, info, uri, metadata, filedata);
1955 g_free (body);
1956 } else {
1957 get_id3v23_tags (frame, &data[pos], csize, info, uri, metadata, filedata);
1958 }
1959
1960 pos += csize;
1961 }
1962
1963 *offset_delta = tsize + 10;
1964 }
1965
1966 static void
1967 parse_id3v20 (const gchar *data,
1968 size_t size,
1969 id3tag *info,
1970 const gchar *uri,
1971 TrackerSparqlBuilder *metadata,
1972 MP3Data *filedata,
1973 size_t *offset_delta)
1974 {
1975 gint unsync;
1976 guint tsize;
1977 guint pos;
1978
1979 if ((size < 16) ||
1980 (data[0] != 0x49) ||
1981 (data[1] != 0x44) ||
1982 (data[2] != 0x33) ||
1983 (data[3] != 0x02) ||
1984 (data[4] != 0x00)) {
1985 return;
1986 }
1987
1988 unsync = (data[5] & 0x80) > 0;
1989 tsize = (((data[6] & 0x7F) << 21) |
1990 ((data[7] & 0x7F) << 14) |
1991 ((data[8] & 0x7F) << 07) |
1992 ((data[9] & 0x7F) << 00));
1993
1994 if (tsize + 10 > size) {
1995 return;
1996 }
1997 pos = 10;
1998
1999 while (pos < size) {
2000 id3v2frame frame;
2001 size_t csize;
2002
2003 if (pos + 6 > size) {
2004 return;
2005 }
2006
2007 frame = id3v2_get_frame (&data[pos]);
2008
2009 csize = (((unsigned char)(data[pos + 3]) << 16) +
2010 ((unsigned char)(data[pos + 4]) << 8) +
2011 ((unsigned char)(data[pos + 5]) ) );
2012
2013 pos += 6;
2014
2015 if (frame == ID3V2_UNKNOWN) {
2016 /* ignore unknown frames */
2017 pos += csize;
2018 continue;
2019 }
2020
2021 if (pos + csize > size) {
2022 break;
2023 } else if (csize == 0) {
2024 continue;
2025 }
2026
2027 /* Early versions do not have unsynch per frame */
2028 if (unsync) {
2029 size_t unsync_size;
2030 gchar *body;
2031
2032 un_unsync (&data[pos], csize, (unsigned char **) &body, &unsync_size);
pointer targets in passing argument 1 of 'un_unsync' differ in signedness
(emitted by gcc)
2033 get_id3v20_tags (frame, body, unsync_size, info, uri, metadata, filedata);
2034 g_free (body);
2035 } else {
2036 get_id3v20_tags (frame, &data[pos], csize, info, uri, metadata, filedata);
2037 }
2038
2039 pos += csize;
2040 }
2041
2042 *offset_delta = tsize + 10;
2043 }
2044
2045 static goffset
2046 parse_id3v2 (const gchar *data,
2047 size_t size,
2048 id3tag *info,
2049 const gchar *uri,
2050 TrackerSparqlBuilder *metadata,
2051 MP3Data *filedata)
2052 {
2053 gboolean done = FALSE;
2054 size_t offset = 0;
2055
2056 do {
2057 size_t offset_delta = 0;
2058 parse_id3v24 (data + offset, size - offset, info, uri, metadata, filedata, &offset_delta);
2059 parse_id3v23 (data + offset, size - offset, info, uri, metadata, filedata, &offset_delta);
2060 parse_id3v20 (data + offset, size - offset, info, uri, metadata, filedata, &offset_delta);
2061
2062 if (offset_delta == 0) {
2063 done = TRUE;
2064 filedata->id3v2_size = offset;
2065 } else {
2066 offset += offset_delta;
2067 }
2068
2069 } while (!done);
2070
2071 return offset;
2072 }
2073
2074 G_MODULE_EXPORT gboolean
2075 tracker_extract_get_metadata (TrackerExtractInfo *info)
2076 {
2077 gchar *filename, *uri;
2078 int fd;
2079 void *buffer;
2080 void *id3v1_buffer;
2081 goffset size;
2082 goffset buffer_size;
2083 goffset audio_offset;
2084 MP3Data md = { 0 };
2085 TrackerSparqlBuilder *metadata, *preupdate;
2086 GFile *file;
2087 const gchar *graph;
2088
2089 graph = tracker_extract_info_get_graph (info);
2090 metadata = tracker_extract_info_get_metadata_builder (info);
2091 preupdate = tracker_extract_info_get_preupdate_builder (info);
2092
2093 file = tracker_extract_info_get_file (info);
2094 filename = g_file_get_path (file);
2095
2096 size = tracker_file_get_size (filename);
2097
2098 if (size == 0) {
2099 g_free (filename);
2100 return FALSE;
2101 }
2102
2103 md.size = size;
2104 buffer_size = MIN (size, MAX_FILE_READ);
2105
2106 fd = tracker_file_open_fd (filename);
2107
2108 if (fd == -1) {
2109 return FALSE;
2110 }
2111
2112 #ifndef G_OS_WIN32
2113 /* We don't use GLib's mmap because size can not be specified */
2114 buffer = mmap (NULL,
2115 buffer_size,
2116 PROT_READ,
2117 MAP_PRIVATE,
2118 fd,
2119 0);
2120 #endif
2121
2122 id3v1_buffer = read_id3v1_buffer (fd, size);
2123
2124 #ifdef HAVE_POSIX_FADVISE
2125 posix_fadvise (fd, 0, 0, POSIX_FADV_DONTNEED);
2126 #endif /* HAVE_POSIX_FADVISE */
2127
2128 close (fd);
2129
2130 if (buffer == NULL || buffer == (void*) -1) {
Uninitialized variable: buffer
(emitted by cppcheck)
2131 g_free (filename);
2132 return FALSE;
2133 }
2134
2135 if (!get_id3 (id3v1_buffer, ID3V1_SIZE, &md.id3v1)) {
2136 /* Do nothing? */
2137 }
2138
2139 g_free (id3v1_buffer);
2140
2141 if (md.id3v1.encoding != NULL) {
2142 gchar *locale;
2143
2144 locale = tracker_locale_get (TRACKER_LOCALE_LANGUAGE);
2145 if (!g_str_has_prefix (locale, "ru") &&
2146 !g_str_has_prefix (locale, "uk")) {
2147 /* use guessed encoding for ID3v2 tags only in selected locales
2148 where broken ID3v2 is widespread */
2149 g_free (md.id3v1.encoding);
2150 md.id3v1.encoding = NULL;
2151 }
2152 g_free (locale);
2153 locale = NULL;
2154 }
2155
2156 /* Get other embedded tags */
2157 uri = g_file_get_uri (file);
2158 audio_offset = parse_id3v2 (buffer, buffer_size, &md.id3v1, uri, metadata, &md);
2159
2160 md.title = tracker_coalesce_strip (4, md.id3v24.title2,
2161 md.id3v23.title2,
2162 md.id3v22.title2,
2163 md.id3v1.title);
2164
2165 md.lyricist = tracker_coalesce_strip (4, md.id3v24.text,
2166 md.id3v23.toly,
2167 md.id3v23.text,
2168 md.id3v22.text);
2169
2170 md.composer = tracker_coalesce_strip (3, md.id3v24.composer,
2171 md.id3v23.composer,
2172 md.id3v22.composer);
2173
2174 md.performer = tracker_coalesce_strip (7, md.id3v24.performer1,
2175 md.id3v24.performer2,
2176 md.id3v23.performer1,
2177 md.id3v23.performer2,
2178 md.id3v22.performer1,
2179 md.id3v22.performer2,
2180 md.id3v1.artist);
2181
2182 md.album = tracker_coalesce_strip (4, md.id3v24.album,
2183 md.id3v23.album,
2184 md.id3v22.album,
2185 md.id3v1.album);
2186
2187 md.genre = tracker_coalesce_strip (7, md.id3v24.content_type,
2188 md.id3v24.title1,
2189 md.id3v23.content_type,
2190 md.id3v23.title1,
2191 md.id3v22.content_type,
2192 md.id3v22.title1,
2193 md.id3v1.genre);
2194
2195 md.recording_time = tracker_coalesce_strip (7, md.id3v24.recording_time,
2196 md.id3v24.release_time,
2197 md.id3v23.recording_time,
2198 md.id3v23.release_time,
2199 md.id3v22.recording_time,
2200 md.id3v22.release_time,
2201 md.id3v1.recording_time);
2202
2203 md.publisher = tracker_coalesce_strip (3, md.id3v24.publisher,
2204 md.id3v23.publisher,
2205 md.id3v22.publisher);
2206
2207 md.copyright = tracker_coalesce_strip (3, md.id3v24.copyright,
2208 md.id3v23.copyright,
2209 md.id3v22.copyright);
2210
2211 md.comment = tracker_coalesce_strip (7, md.id3v24.title3,
2212 md.id3v24.comment,
2213 md.id3v23.title3,
2214 md.id3v23.comment,
2215 md.id3v22.title3,
2216 md.id3v22.comment,
2217 md.id3v1.comment);
2218
2219 md.encoded_by = tracker_coalesce_strip (3, md.id3v24.encoded_by,
2220 md.id3v23.encoded_by,
2221 md.id3v22.encoded_by);
2222
2223 if (md.id3v24.track_number != 0) {
2224 md.track_number = md.id3v24.track_number;
2225 } else if (md.id3v23.track_number != 0) {
2226 md.track_number = md.id3v23.track_number;
2227 } else if (md.id3v22.track_number != 0) {
2228 md.track_number = md.id3v22.track_number;
2229 } else if (md.id3v1.track_number != 0) {
2230 md.track_number = md.id3v1.track_number;
2231 }
2232
2233 if (md.id3v24.track_count != 0) {
2234 md.track_count = md.id3v24.track_count;
2235 } else if (md.id3v23.track_count != 0) {
2236 md.track_count = md.id3v23.track_count;
2237 } else if (md.id3v22.track_count != 0) {
2238 md.track_count = md.id3v22.track_count;
2239 }
2240
2241 if (md.id3v24.set_number != 0) {
2242 md.set_number = md.id3v24.set_number;
2243 } else if (md.id3v23.set_number != 0) {
2244 md.set_number = md.id3v23.set_number;
2245 } else if (md.id3v22.set_number != 0) {
2246 md.set_number = md.id3v22.set_number;
2247 }
2248
2249 if (md.id3v24.set_count != 0) {
2250 md.set_count = md.id3v24.set_count;
2251 } else if (md.id3v23.set_count != 0) {
2252 md.set_count = md.id3v23.set_count;
2253 } else if (md.id3v22.set_count != 0) {
2254 md.set_count = md.id3v22.set_count;
2255 }
2256
2257 if (md.performer) {
2258 md.performer_uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", md.performer);
2259
2260 tracker_sparql_builder_insert_open (preupdate, NULL);
2261 if (graph) {
2262 tracker_sparql_builder_graph_open (preupdate, graph);
2263 }
2264
2265 tracker_sparql_builder_subject_iri (preupdate, md.performer_uri);
2266 tracker_sparql_builder_predicate (preupdate, "a");
2267 tracker_sparql_builder_object (preupdate, "nmm:Artist");
2268 tracker_sparql_builder_predicate (preupdate, "nmm:artistName");
2269 tracker_sparql_builder_object_unvalidated (preupdate, md.performer);
2270
2271 if (graph) {
2272 tracker_sparql_builder_graph_close (preupdate);
2273 }
2274 tracker_sparql_builder_insert_close (preupdate);
2275 }
2276
2277 if (md.composer) {
2278 md.composer_uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", md.composer);
2279
2280 tracker_sparql_builder_insert_open (preupdate, NULL);
2281 if (graph) {
2282 tracker_sparql_builder_graph_open (preupdate, graph);
2283 }
2284
2285 tracker_sparql_builder_subject_iri (preupdate, md.composer_uri);
2286 tracker_sparql_builder_predicate (preupdate, "a");
2287 tracker_sparql_builder_object (preupdate, "nmm:Artist");
2288 tracker_sparql_builder_predicate (preupdate, "nmm:artistName");
2289 tracker_sparql_builder_object_unvalidated (preupdate, md.composer);
2290
2291 if (graph) {
2292 tracker_sparql_builder_graph_close (preupdate);
2293 }
2294 tracker_sparql_builder_insert_close (preupdate);
2295 }
2296
2297 if (md.lyricist) {
2298 md.lyricist_uri = tracker_sparql_escape_uri_printf ("urn:artist:%s", md.lyricist);
2299
2300 tracker_sparql_builder_insert_open (preupdate, NULL);
2301 if (graph) {
2302 tracker_sparql_builder_graph_open (preupdate, graph);
2303 }
2304
2305 tracker_sparql_builder_subject_iri (preupdate, md.lyricist_uri);
2306 tracker_sparql_builder_predicate (preupdate, "a");
2307 tracker_sparql_builder_object (preupdate, "nmm:Artist");
2308 tracker_sparql_builder_predicate (preupdate, "nmm:artistName");
2309 tracker_sparql_builder_object_unvalidated (preupdate, md.lyricist);
2310
2311 if (graph) {
2312 tracker_sparql_builder_graph_close (preupdate);
2313 }
2314 tracker_sparql_builder_insert_close (preupdate);
2315 }
2316
2317 if (md.album) {
2318 md.album_uri = tracker_sparql_escape_uri_printf ("urn:album:%s", md.album);
2319
2320 tracker_sparql_builder_insert_open (preupdate, NULL);
2321 if (graph) {
2322 tracker_sparql_builder_graph_open (preupdate, graph);
2323 }
2324
2325 tracker_sparql_builder_subject_iri (preupdate, md.album_uri);
2326 tracker_sparql_builder_predicate (preupdate, "a");
2327 tracker_sparql_builder_object (preupdate, "nmm:MusicAlbum");
2328 /* FIXME: nmm:albumTitle is now deprecated
2329 * tracker_sparql_builder_predicate (preupdate, "nie:title");
2330 */
2331 tracker_sparql_builder_predicate (preupdate, "nmm:albumTitle");
2332 tracker_sparql_builder_object_unvalidated (preupdate, md.album);
2333
2334 if (md.performer_uri) {
2335 tracker_sparql_builder_predicate (preupdate, "nmm:albumArtist");
2336 tracker_sparql_builder_object_iri (preupdate, md.performer_uri);
2337 }
2338
2339 if (graph) {
2340 tracker_sparql_builder_graph_close (preupdate);
2341 }
2342 tracker_sparql_builder_insert_close (preupdate);
2343
2344 if (md.track_count > 0) {
2345 tracker_sparql_builder_delete_open (preupdate, NULL);
2346 tracker_sparql_builder_subject_iri (preupdate, md.album_uri);
2347 tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
2348 tracker_sparql_builder_object_variable (preupdate, "unknown");
2349 tracker_sparql_builder_delete_close (preupdate);
2350 tracker_sparql_builder_where_open (preupdate);
2351 tracker_sparql_builder_subject_iri (preupdate, md.album_uri);
2352 tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
2353 tracker_sparql_builder_object_variable (preupdate, "unknown");
2354 tracker_sparql_builder_where_close (preupdate);
2355
2356 tracker_sparql_builder_insert_open (preupdate, NULL);
2357 if (graph) {
2358 tracker_sparql_builder_graph_open (preupdate, graph);
2359 }
2360
2361 tracker_sparql_builder_subject_iri (preupdate, md.album_uri);
2362 tracker_sparql_builder_predicate (preupdate, "nmm:albumTrackCount");
2363 tracker_sparql_builder_object_int64 (preupdate, md.track_count);
2364
2365 if (graph) {
2366 tracker_sparql_builder_graph_close (preupdate);
2367 }
2368 tracker_sparql_builder_insert_close (preupdate);
2369 }
2370 }
2371
2372 tracker_sparql_builder_predicate (metadata, "a");
2373 tracker_sparql_builder_object (metadata, "nmm:MusicPiece");
2374 tracker_sparql_builder_object (metadata, "nfo:Audio");
2375
2376 tracker_guarantee_title_from_file (metadata,
2377 "nie:title",
2378 md.title,
2379 uri,
2380 NULL);
2381
2382 if (md.lyricist_uri) {
2383 tracker_sparql_builder_predicate (metadata, "nmm:lyricist");
2384 tracker_sparql_builder_object_iri (metadata, md.lyricist_uri);
2385 g_free (md.lyricist_uri);
2386 }
2387
2388 if (md.performer_uri) {
2389 tracker_sparql_builder_predicate (metadata, "nmm:performer");
2390 tracker_sparql_builder_object_iri (metadata, md.performer_uri);
2391 g_free (md.performer_uri);
2392 }
2393
2394 if (md.composer_uri) {
2395 tracker_sparql_builder_predicate (metadata, "nmm:composer");
2396 tracker_sparql_builder_object_iri (metadata, md.composer_uri);
2397 g_free (md.composer_uri);
2398 }
2399
2400 if (md.album_uri) {
2401 tracker_sparql_builder_predicate (metadata, "nmm:musicAlbum");
2402 tracker_sparql_builder_object_iri (metadata, md.album_uri);
2403 }
2404
2405 if (md.recording_time) {
2406 tracker_sparql_builder_predicate (metadata, "nie:contentCreated");
2407 tracker_sparql_builder_object_unvalidated (metadata, md.recording_time);
2408 }
2409
2410 if (md.genre) {
2411 tracker_sparql_builder_predicate (metadata, "nfo:genre");
2412 tracker_sparql_builder_object_unvalidated (metadata, md.genre);
2413 }
2414
2415 if (md.copyright) {
2416 tracker_sparql_builder_predicate (metadata, "nie:copyright");
2417 tracker_sparql_builder_object_unvalidated (metadata, md.copyright);
2418 }
2419
2420 if (md.comment) {
2421 tracker_sparql_builder_predicate (metadata, "nie:comment");
2422 tracker_sparql_builder_object_unvalidated (metadata, md.comment);
2423 }
2424
2425 if (md.publisher) {
2426 tracker_sparql_builder_predicate (metadata, "nco:publisher");
2427 tracker_sparql_builder_object_blank_open (metadata);
2428 tracker_sparql_builder_predicate (metadata, "a");
2429 tracker_sparql_builder_object (metadata, "nco:Contact");
2430 tracker_sparql_builder_predicate (metadata, "nco:fullname");
2431 tracker_sparql_builder_object_unvalidated (metadata, md.publisher);
2432 tracker_sparql_builder_object_blank_close (metadata);
2433 }
2434
2435 if (md.encoded_by) {
2436 tracker_sparql_builder_predicate (metadata, "nfo:encodedBy");
2437 tracker_sparql_builder_object_unvalidated (metadata, md.encoded_by);
2438 }
2439
2440 if (md.track_number > 0) {
2441 tracker_sparql_builder_predicate (metadata, "nmm:trackNumber");
2442 tracker_sparql_builder_object_int64 (metadata, md.track_number);
2443 }
2444
2445 if (md.album) {
2446 gchar *album_disc_uri;
2447
2448 album_disc_uri = tracker_sparql_escape_uri_printf ("urn:album-disc:%s:Disc%d",
2449 md.album,
2450 md.set_number > 0 ? md.set_number : 1);
2451
2452 tracker_sparql_builder_delete_open (preupdate, NULL);
2453 tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
2454 tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
2455 tracker_sparql_builder_object_variable (preupdate, "unknown");
2456 tracker_sparql_builder_delete_close (preupdate);
2457 tracker_sparql_builder_where_open (preupdate);
2458 tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
2459 tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
2460 tracker_sparql_builder_object_variable (preupdate, "unknown");
2461 tracker_sparql_builder_where_close (preupdate);
2462
2463 tracker_sparql_builder_delete_open (preupdate, NULL);
2464 tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
2465 tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
2466 tracker_sparql_builder_object_variable (preupdate, "unknown");
2467 tracker_sparql_builder_delete_close (preupdate);
2468 tracker_sparql_builder_where_open (preupdate);
2469 tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
2470 tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
2471 tracker_sparql_builder_object_variable (preupdate, "unknown");
2472 tracker_sparql_builder_where_close (preupdate);
2473
2474 tracker_sparql_builder_insert_open (preupdate, NULL);
2475 if (graph) {
2476 tracker_sparql_builder_graph_open (preupdate, graph);
2477 }
2478
2479 tracker_sparql_builder_subject_iri (preupdate, album_disc_uri);
2480 tracker_sparql_builder_predicate (preupdate, "a");
2481 tracker_sparql_builder_object (preupdate, "nmm:MusicAlbumDisc");
2482 tracker_sparql_builder_predicate (preupdate, "nmm:setNumber");
2483 tracker_sparql_builder_object_int64 (preupdate, md.set_number > 0 ? md.set_number : 1);
2484 tracker_sparql_builder_predicate (preupdate, "nmm:albumDiscAlbum");
2485 tracker_sparql_builder_object_iri (preupdate, md.album_uri);
2486
2487 if (graph) {
2488 tracker_sparql_builder_graph_close (preupdate);
2489 }
2490 tracker_sparql_builder_insert_close (preupdate);
2491
2492 tracker_sparql_builder_predicate (metadata, "nmm:musicAlbumDisc");
2493 tracker_sparql_builder_object_iri (metadata, album_disc_uri);
2494
2495 g_free (album_disc_uri);
2496 }
2497
2498 g_free (md.album_uri);
2499
2500 /* Get mp3 stream info */
2501 mp3_parse (buffer, buffer_size, audio_offset, uri, metadata, &md);
2502
2503 tracker_media_art_process (md.media_art_data,
2504 md.media_art_size,
2505 md.media_art_mime,
2506 TRACKER_MEDIA_ART_ALBUM,
2507 md.performer,
2508 md.album,
2509 uri);
2510 g_free (md.media_art_data);
2511 g_free (md.media_art_mime);
2512
2513 id3v2tag_free (&md.id3v22);
2514 id3v2tag_free (&md.id3v23);
2515 id3v2tag_free (&md.id3v24);
2516 id3tag_free (&md.id3v1);
2517
2518 #ifndef G_OS_WIN32
2519 munmap (buffer, buffer_size);
2520 #endif
2521
2522 g_free (filename);
2523 g_free (uri);
2524
2525 return TRUE;
2526 }