blob: b15853154bda5f9c207843afa5c1936c81138b76 [file] [log] [blame]
Josh Coalson412fa3b2002-07-11 06:15:30 +00001/* libxmms-flac - XMMS FLAC input plugin
2 * Copyright (C) 2000,2001,2002 Josh Coalson
3 * Copyright (C) 2002 Daisuke Shimamura
4 *
5 * Based on FLAC plugin.c and mpg123 plugin
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22#include <stdlib.h>
23#include <string.h>
24#include <stdio.h>
25#include <glib.h>
26#include <xmms/plugin.h>
27#include <xmms/util.h>
28#include <xmms/configfile.h>
29#include <xmms/titlestring.h>
30
31#include "mylocale.h"
32#include "configure.h"
33
34#ifdef FLAC__HAS_ID3LIB
35#include <id3.h>
36#include "id3_tag.h"
37
38#else
39#include "charset.h"
40#include "genres.h"
41
42typedef struct id3v1tag_t {
43 char tag[3]; /* always "TAG": defines ID3v1 tag 128 bytes before EOF */
44 char title[30];
45 char artist[30];
46 char album[30];
47 char year[4];
48 union {
49 struct {
50 char comment[30];
51 } v1_0;
52 struct {
53 char comment[28];
54 char __zero;
55 unsigned char track;
56 } v1_1;
57 } u;
58 unsigned char genre;
59} id3v1_struct;
60
61typedef struct id3tag_t {
62 char title[64];
63 char artist[64];
64 char album[64];
65 char comment[256];
66 char genre[256];
67 char year[16];
68 char track[16];
69} id3v2_struct;
70
71static gboolean get_id3v1_tag_as_v2_(const char *filename, id3v2_struct *tag);
72static void flac_id3v1_to_id3v2(id3v1_struct *v1, id3v2_struct *v2);
73static const char *flac_get_id3_genre(unsigned char genre_code);
74#endif /* FLAC__HAS_ID3LIB */
75
76static gchar *extname(const char *filename);
77static char* flac_getstr(char* str);
78static int flac_getnum(char* str);
79
80/*
81 * Function flac_format_song_title (tag, filename)
82 *
83 * Create song title according to `tag' and/or `filename' and
84 * return it. The title must be subsequently freed using g_free().
85 *
86 */
87gchar *flac_format_song_title(gchar * filename)
88{
89 gchar *ret = NULL;
90 TitleInput *input = NULL;
91 gboolean rc;
92
93#ifdef FLAC__HAS_ID3LIB
94 File_Tag tag;
95 Initialize_File_Tag_Item (&tag);
96 rc = Id3tag_Read_File_Tag (filename, &tag);
97#else
98 id3v2_struct tag;
99 memset(&tag, 0, sizeof(tag));
100 rc = get_id3v1_tag_as_v2_(filename, &tag);
101#endif
102 XMMS_NEW_TITLEINPUT(input);
103
104 if (rc)
105 {
106 input->performer = flac_getstr(tag.artist);
107 input->album_name = flac_getstr(tag.album);
108 input->track_name = flac_getstr(tag.title);
109 input->track_number = flac_getnum(tag.track);
110 input->year = flac_getnum(tag.year);
111 input->genre = flac_getstr(tag.genre);
112 input->comment = flac_getstr(tag.comment);
113 }
114 input->file_name = g_basename(filename);
115 input->file_path = filename;
116 input->file_ext = extname(filename);
117 ret = xmms_get_titlestring(flac_cfg.tag_override ?
118 flac_cfg.tag_format :
119 xmms_get_gentitle_format(), input);
120 g_free(input);
121
122 if (!ret)
123 {
124 /*
125 * Format according to filename.
126 */
127 ret = g_strdup(g_basename(filename));
128 if (extname(ret) != NULL)
129 *(extname(ret) - 1) = '\0'; /* removes period */
130 }
131
132#ifdef FLAC__HAS_ID3LIB
133 Free_File_Tag_Item (&tag);
134#endif
135 return ret;
136}
137
138/*
139 * Function extname (filename)
140 *
141 * Return pointer within filename to its extenstion, or NULL if
142 * filename has no extension.
143 *
144 */
145static gchar *extname(const char *filename)
146{
147 gchar *ext = strrchr(filename, '.');
148
149 if (ext != NULL)
150 ++ext;
151
152 return ext;
153}
154
155static char* flac_getstr(char* str)
156{
157 if (str && strlen(str) > 0)
158 return str;
159 return NULL;
160}
161
162static int flac_getnum(char* str)
163{
164 if (str && strlen(str) > 0)
165 return atoi(str);
166 return 0;
167}
168
169#ifndef FLAC__HAS_ID3LIB
170/*
171 * Function get_idv2_tag_(filename, ID3v2tag)
172 *
173 * Get ID3v2 tag from file.
174 *
175 */
176static gboolean get_id3v1_tag_as_v2_(const char *filename, id3v2_struct *id3v2tag)
177{
178 FILE *file;
179 id3v1_struct id3v1tag;
180
181 memset(id3v2tag, 0, sizeof(id3v2_struct));
182
183 if ((file = fopen(filename, "rb")) != 0)
184 {
185 if ((fseek(file, -1 * sizeof (id3v1tag), SEEK_END) == 0) &&
186 (fread(&id3v1tag, 1, sizeof (id3v1tag), file) == sizeof (id3v1tag)) &&
187 (strncmp(id3v1tag.tag, "TAG", 3) == 0))
188 {
189 flac_id3v1_to_id3v2(&id3v1tag, id3v2tag);
190
191 if (flac_cfg.convert_char_set)
192 {
193 gchar *string;
194
195 string = convert_from_file_to_user(id3v2tag->title);
196 strcpy(id3v2tag->title, string);
197 g_free(string);
198
199 string = convert_from_file_to_user(id3v2tag->artist);
200 strcpy(id3v2tag->artist, string);
201 g_free(string);
202
203 string = convert_from_file_to_user(id3v2tag->album);
204 strcpy(id3v2tag->album, string);
205 g_free(string);
206
207 string = convert_from_file_to_user(id3v2tag->comment);
208 strcpy(id3v2tag->comment, string);
209 g_free(string);
210
211 string = convert_from_file_to_user(id3v2tag->genre);
212 strcpy(id3v2tag->genre, string);
213 g_free(string);
214
215 string = convert_from_file_to_user(id3v2tag->year);
216 strcpy(id3v2tag->year, string);
217 g_free(string);
218
219 string = convert_from_file_to_user(id3v2tag->track);
220 strcpy(id3v2tag->track, string);
221 g_free(string);
222 }
223 }
224
225 }
226 else
227 {
228 return FALSE;
229 }
230
231 return TRUE;
232}
233
234/*
235 * Function flac_id3v1_to_id3v2 (v1, v2)
236 *
237 * Convert ID3v1 tag `v1' to ID3v2 tag `v2'.
238 *
239 */
240static void flac_id3v1_to_id3v2(id3v1_struct *v1, id3v2_struct *v2)
241{
242 memset(v2,0,sizeof(id3v2_struct));
243 strncpy(v2->title, v1->title, 30);
244 strncpy(v2->artist, v1->artist, 30);
245 strncpy(v2->album, v1->album, 30);
246 strncpy(v2->comment, v1->u.v1_0.comment, 30);
247 strncpy(v2->genre, flac_get_id3_genre(v1->genre), sizeof (v2->genre));
248 strncpy(v2->year, v1->year, 4);
249
250 /* Check for v1.1 tags. */
251 if (v1->u.v1_1.__zero == 0)
252 sprintf(v2->track, "%d", v1->u.v1_1.track);
253 else
254 strcpy(v2->track, "0");
255
256 g_strstrip(v2->title);
257 g_strstrip(v2->artist);
258 g_strstrip(v2->album);
259 g_strstrip(v2->comment);
260 g_strstrip(v2->genre);
261 g_strstrip(v2->year);
262 g_strstrip(v2->track);
263}
264
265static const char *flac_get_id3_genre(unsigned char genre_code)
266{
267 if (genre_code < GENRE_MAX)
268 return gettext(id3_genres[genre_code]);
269
270 return "";
271}
272#endif /* ifndef FLAC__HAS_ID3LIB */