1 /* id3read.c
2    interface for the id3tag library
3    Copyright (C) 2001 Linus Walleij
4 
5 This file is part of the GNOMAD package.
6 
7 GNOMAD is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11 
12 You should have received a copy of the GNU General Public License
13 along with GNOMAD; see the file COPYING.  If not, write to
14 the Free Software Foundation, 59 Temple Place - Suite 330,
15 Boston, MA 02111-1307, USA.
16 
17 */
18 
19 #define ID3V2_MAX_STRING_LEN 4096
20 #include <id3tag.h>
21 #include <libmtp.h>
22 #include <stdlib.h>		/* atol() */
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <glib.h>
29 #include <glib/gstdio.h>
30 
31 /* Converts a figure representing a number of seconds to
32  *  * a string in mm:ss notation */
33 gchar *
seconds_to_mmss(uint32_t seconds)34 seconds_to_mmss (uint32_t seconds)
35 {
36   gchar tmp2[10];
37   gchar tmp[10];
38   uint32_t secfrac = seconds % 60;
39   uint32_t minfrac = seconds / 60;
40 
41   if (seconds == 0)
42     return g_strdup ("0:00");
43 
44   snprintf (tmp2, 10, "0%u", secfrac);
45   while (strlen (tmp2) > 2)
46     {
47       tmp2[0] = tmp2[1];
48       tmp2[1] = tmp2[2];
49       tmp2[2] = '\0';
50     }
51   snprintf (tmp, 10, "%u:%s", minfrac, tmp2);
52   return g_strdup (tmp);
53 }
54 
55 /* Converts a string in mm:ss notation to a figure
56  *  * representing seconds */
57 guint
mmss_to_seconds(gchar * mmss)58 mmss_to_seconds (gchar * mmss)
59 {
60   gchar **tmp;
61   guint seconds = 0;
62 
63   if (!mmss)
64     return seconds;
65 
66   tmp = g_strsplit (mmss, ":", 0);
67   if (tmp[1] != NULL)
68     {
69       seconds = 60 * strtoul (tmp[0], NULL, 10);
70       seconds += strtoul (tmp[1], NULL, 10);
71     }
72   if (tmp != NULL)
73     g_strfreev (tmp);
74   return seconds;
75 }
76 
77 /* Eventually make charset selectable */
78 
79 static id3_utf8_t *
charset_to_utf8(const id3_latin1_t * str)80 charset_to_utf8 (const id3_latin1_t * str)
81 {
82   id3_utf8_t *tmp;
83 
84   tmp =
85     (id3_utf8_t *) g_convert ((gchar *) str, -1, "UTF-8", "ISO-8859-1",
86 			      NULL, NULL, NULL);
87   return (id3_utf8_t *) tmp;
88 }
89 
90 /*****************************************************************************
91  * ID3TAG interface
92  * Many parts of this code copied in from gtkpod or plagiated, I confess.
93  * Acknowledgements to Jorg Schuler for that...
94  *****************************************************************************/
95 
96 /*
97  * Returns a text frame, or NULL
98  */
99 
100 static gchar *
getFrameText(struct id3_tag * tag,char * frame_name)101 getFrameText (struct id3_tag *tag, char *frame_name)
102 {
103   const id3_ucs4_t *string;
104   struct id3_frame *frame;
105   union id3_field *field;
106   gchar *utf8 = NULL;
107   enum id3_field_textencoding encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1;
108 
109   frame = id3_tag_findframe (tag, frame_name, 0);
110   if (!frame)
111     return NULL;
112 
113   /* Find the encoding used for the field */
114   field = id3_frame_field (frame, 0);
115   //printf ("field: %p\n", field);
116   if (field && (id3_field_type (field) == ID3_FIELD_TYPE_TEXTENCODING))
117     {
118       encoding = field->number.value;
119       //printf ("encoding: %d\n", encoding);
120     }
121 
122   if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
123     field = id3_frame_field (frame, 3);
124   else
125     field = id3_frame_field (frame, 1);
126 
127   //printf ("field: %p\n", field);
128 
129   if (!field)
130     return NULL;
131 
132   if (strcmp (frame_name, ID3_FRAME_COMMENT) == 0)
133     string = id3_field_getfullstring (field);
134   else
135     string = id3_field_getstrings (field, 0);
136 
137   // g_debug("string: %s\n", string);
138 
139   if (!string)
140     return NULL;
141 
142   if (strcmp (frame_name, ID3_FRAME_GENRE) == 0)
143     string = id3_genre_name (string);
144 
145   if (encoding == ID3_FIELD_TEXTENCODING_ISO_8859_1)
146     {
147       /* ISO_8859_1 is just a "marker" -- most people just drop
148          whatever coding system they are using into it, so we use
149          charset_to_utf8() to convert to utf8 */
150       id3_latin1_t *raw = id3_ucs4_latin1duplicate (string);
151       utf8 = (gchar *) charset_to_utf8 (raw);
152       g_free (raw);
153     }
154   else
155     {
156       /* Standard unicode is being used -- we won't have to worry
157          about charsets then. */
158       // g_debug("This frame is a Unicode frame!\n");
159       utf8 = (gchar *) id3_ucs4_utf8duplicate (string);
160     }
161   // g_debug("Found tag: %s, value: %s\n", frame_name, utf8);
162   return utf8;
163 }
164 
165 /*****************************************************************************
166  * FUNCTIONS FOR GETTING ID3v2 FIELDS
167  *****************************************************************************/
168 
169 gchar *
getArtist(struct id3_tag * tag)170 getArtist (struct id3_tag * tag)
171 {
172   gchar *artname = NULL;
173 
174   artname = getFrameText (tag, "TPE1");
175   if (artname == NULL)
176     artname = getFrameText (tag, "TPE2");
177   if (artname == NULL)
178     artname = getFrameText (tag, "TPE3");
179   if (artname == NULL)
180     artname = getFrameText (tag, "TPE4");
181   if (artname == NULL)
182     artname = getFrameText (tag, "TCOM");
183   return artname;
184 }
185 
186 gchar *
getTitle(struct id3_tag * tag)187 getTitle (struct id3_tag * tag)
188 {
189   return getFrameText (tag, "TIT2");
190 }
191 
192 gchar *
getAlbum(struct id3_tag * tag)193 getAlbum (struct id3_tag * tag)
194 {
195   return getFrameText (tag, "TALB");
196 }
197 
198 gchar *
getYear(struct id3_tag * tag)199 getYear (struct id3_tag * tag)
200 {
201   gchar *year = NULL;
202 
203   year = getFrameText (tag, "TYER");
204   if (year == NULL)
205     {
206       year = getFrameText (tag, "TDRC");
207     }
208   if (year == NULL)
209     {
210       year = g_strdup ("None");
211     }
212   return year;
213 }
214 
215 gchar *
getGenre(struct id3_tag * tag)216 getGenre (struct id3_tag * tag)
217 {
218   return getFrameText (tag, "TCON");
219 }
220 
221 int
getSonglen(struct id3_tag * tag)222 getSonglen (struct id3_tag *tag)
223 {
224   gchar *timetext;
225   long milliseconds;
226   int seconds;
227 
228   timetext = getFrameText (tag, "TLEN");
229   if (timetext == NULL)
230     return -1;
231 
232   // g_debug("Found time tag TLEN: %s ms ... ", timetext);
233   milliseconds = atol (timetext);
234   g_free (timetext);
235 
236   if (milliseconds > 0)
237     {
238       seconds = (int) milliseconds / 1000;
239       // g_debug("%d milliseconds is %d seconds.\n", milliseconds, seconds);
240       return seconds;
241     }
242 
243   g_debug ("ID3v2 TLEN tag time was 0\n");
244 
245   return -1;
246 }
247 
248 gchar *
getTracknum(struct id3_tag * tag)249 getTracknum (struct id3_tag * tag)
250 {
251   gchar trackno[40];
252   gchar *trackstr = getFrameText (tag, "TRCK");
253   gchar *posstr = getFrameText (tag, "TPOS");
254   gint i;
255 
256   if (trackstr == NULL)
257     {
258       return NULL;
259     }
260   trackno[0] = '\0';
261   // Take care of any a/b formats
262   for (i = 0; i < strlen (trackstr); i++)
263     {
264       if (trackstr[i] == '/')
265 	{
266 	  // Terminate it at switch character
267 	  trackstr[i] = '\0';
268 	  break;
269 	}
270     }
271   // "Part of set" variable
272   if (posstr != NULL)
273     {
274       // Same a/b format problem again
275       for (i = 0; i < strlen (posstr); i++)
276 	{
277 	  if (posstr[i] == '/')
278 	    {
279 	      // Terminate it at switch character
280 	      posstr[i] = '\0';
281 	      break;
282 	    }
283 	}
284       strncpy (trackno, posstr, sizeof (trackno));
285       if (strlen (trackstr) == 1)
286 	{
287 	  strcat (trackno, "0");
288 	}
289       strncat (trackno, trackstr, sizeof (trackno) - strlen (trackno) - 1);
290       g_free (trackstr);
291       g_free (posstr);
292     }
293   else
294     {
295       strncpy (trackno, trackstr, sizeof (trackno));
296       g_free (trackstr);
297     }
298   // Terminate and return
299   trackno[sizeof (trackno) - 1] = '\0';
300   return g_strdup (trackno);
301 }
302 
303 gchar *
getOrigFilename(struct id3_tag * tag)304 getOrigFilename (struct id3_tag * tag)
305 {
306   return getFrameText (tag, "TOFN");
307 }
308