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