Contents of /trunk/xmms/patches/xmms-1.2.10-id3v2edit.patch
Parent Directory | Revision Log
Revision 153 -
(show annotations)
(download)
Tue May 8 20:52:56 2007 UTC (17 years, 4 months ago) by niro
File size: 108172 byte(s)
Tue May 8 20:52:56 2007 UTC (17 years, 4 months ago) by niro
File size: 108172 byte(s)
-import
1 | diff -Naur xmms-1.2.9-orig/Input/mpg123/charset.h xmms-1.2.9/Input/mpg123/charset.h |
2 | --- xmms-1.2.9-orig/Input/mpg123/charset.h Wed Dec 31 19:00:00 1969 |
3 | +++ xmms-1.2.9/Input/mpg123/charset.h Thu Jan 29 05:20:31 2004 |
4 | @@ -0,0 +1,420 @@ |
5 | +/* charset.h - 2001/12/04 */ |
6 | +/* |
7 | + * EasyTAG - Tag editor for MP3 and OGG files |
8 | + * Copyright (C) 2000-2002 Jerome Couderc <j.couderc@ifrance.com> |
9 | + * |
10 | + * This program is free software; you can redistribute it and/or modify |
11 | + * it under the terms of the GNU General Public License as published by |
12 | + * the Free Software Foundation; either version 2 of the License, or |
13 | + * (at your option) any later version. |
14 | + * |
15 | + * This program is distributed in the hope that it will be useful, |
16 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | + * GNU General Public License for more details. |
19 | + * |
20 | + * You should have received a copy of the GNU General Public License |
21 | + * along with this program; if not, write to the Free Software |
22 | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
23 | + */ |
24 | + |
25 | +#ifndef FALSE |
26 | +#define FALSE 0 |
27 | +#endif |
28 | +#ifndef TRUE |
29 | +#define TRUE 1 |
30 | +#endif |
31 | + |
32 | +/* |
33 | + * Standard gettext macros. |
34 | + */ |
35 | +#ifdef ENABLE_NLS |
36 | +# include <libintl.h> |
37 | +# define _(String) gettext (String) |
38 | +# ifdef gettext_noop |
39 | +# define N_(String) gettext_noop (String) |
40 | +# else |
41 | +# define N_(String) (String) |
42 | +# endif |
43 | +#else |
44 | +# define textdomain(String) (String) |
45 | +# define gettext(String) (String) |
46 | +# define dgettext(Domain,Message) (Message) |
47 | +# define dcgettext(Domain,Message,Type) (Message) |
48 | +# define bindtextdomain(Domain,Directory) (Domain) |
49 | +# define _(String) (String) |
50 | +# define N_(String) (String) |
51 | +#endif |
52 | + |
53 | +#ifndef DLL_H |
54 | +#define DLL_H |
55 | +typedef struct DLL_s |
56 | +{ |
57 | + void *prev; |
58 | + void *data; |
59 | + void *next; |
60 | +} DLL; |
61 | +#endif |
62 | + |
63 | +#ifndef __CHARSET_H__ |
64 | +#define __CHARSET_H__ |
65 | + |
66 | + |
67 | +/*************** |
68 | + * Declaration * |
69 | + ***************/ |
70 | + |
71 | +typedef struct { |
72 | + char *charset_title; |
73 | + char *charset_name; |
74 | +} CharsetInfo; |
75 | + |
76 | + |
77 | +/************** |
78 | + * Prototypes * |
79 | + **************/ |
80 | + |
81 | +//static gchar* get_current_charset (void); |
82 | + |
83 | +/* Used for ogg tags */ |
84 | +char* convert_to_utf8 (const char *string); |
85 | +char* convert_from_utf8 (const char *string); |
86 | + |
87 | +char* convert_from_file_to_user (const char *string); |
88 | +char* convert_from_user_to_file (const char *string); |
89 | + |
90 | +DLL *Charset_Create_List (void); |
91 | +char *Charset_Get_Name_From_Title (char *charset_title); |
92 | +char *Charset_Get_Title_From_Name (char *charset_name); |
93 | + |
94 | +short int test_conversion_charset (char *from, char *to); |
95 | + |
96 | + |
97 | +#endif /* __CHARSET_H__ */ |
98 | + |
99 | +/* |
100 | + * Main part of code, written by: |
101 | + * |
102 | + * Copyright (C) 1999-2001 Håvard Kvålen <havardk@xmms.org> |
103 | + * |
104 | + * This program is free software; you can redistribute it and/or |
105 | + * modify it under the terms of the GNU General Public License |
106 | + * as published by the Free Software Foundation; either version 2 |
107 | + * of the License, or (at your option) any later version. |
108 | + * |
109 | + * This program is distributed in the hope that it will be useful, |
110 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
111 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
112 | + * GNU General Public License for more details. |
113 | + * |
114 | + * You should have received a copy of the GNU General Public License |
115 | + * along with this program; if not, write to the Free Software |
116 | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
117 | + * 02111-1307, USA. |
118 | + * |
119 | + */ |
120 | + |
121 | +#include <stdlib.h> |
122 | +#include <string.h> |
123 | +#include <errno.h> |
124 | + |
125 | +#ifdef HAVE_ICONV_OPEN |
126 | +#include <iconv.h> |
127 | +#endif |
128 | + |
129 | +#ifdef HAVE_LANGINFO_CODESET |
130 | +#include <langinfo.h> |
131 | +#endif |
132 | + |
133 | +/**************** |
134 | + * Declarations * |
135 | + ****************/ |
136 | + |
137 | +#define CHARSET_TRANS_ARRAY_LEN ( sizeof(charset_trans_array) / sizeof((charset_trans_array)[0]) ) |
138 | +const CharsetInfo charset_trans_array[] = { |
139 | + {N_("Arabic (IBM-864)"), "IBM864" }, |
140 | + {N_("Arabic (ISO-8859-6)"), "ISO-8859-6" }, |
141 | + {N_("Arabic (Windows-1256)"), "windows-1256" }, |
142 | + {N_("Baltic (ISO-8859-13)"), "ISO-8859-13" }, |
143 | + {N_("Baltic (ISO-8859-4)"), "ISO-8859-4" }, |
144 | + {N_("Baltic (Windows-1257)"), "windows-1257" }, |
145 | + {N_("Celtic (ISO-8859-14)"), "ISO-8859-14" }, |
146 | + {N_("Central European (IBM-852)"), "IBM852" }, |
147 | + {N_("Central European (ISO-8859-2)"), "ISO-8859-2" }, |
148 | + {N_("Central European (Windows-1250)"), "windows-1250" }, |
149 | + {N_("Chinese Simplified (GB18030)"), "gb18030" }, |
150 | + {N_("Chinese Simplified (GB2312)"), "GB2312" }, |
151 | + {N_("Chinese Traditional (Big5)"), "Big5" }, |
152 | + {N_("Chinese Traditional (Big5-HKSCS)"), "Big5-HKSCS" }, |
153 | + {N_("Cyrillic (IBM-855)"), "IBM855" }, |
154 | + {N_("Cyrillic (ISO-8859-5)"), "ISO-8859-5" }, |
155 | + {N_("Cyrillic (ISO-IR-111)"), "ISO-IR-111" }, |
156 | + {N_("Cyrillic (KOI8-R)"), "KOI8-R" }, |
157 | + {N_("Cyrillic (Windows-1251)"), "windows-1251" }, |
158 | + {N_("Cyrillic/Russian (CP-866)"), "IBM866" }, |
159 | + {N_("Cyrillic/Ukrainian (KOI8-U)"), "KOI8-U" }, |
160 | + {N_("English (US-ASCII)"), "us-ascii" }, |
161 | + {N_("Greek (ISO-8859-7)"), "ISO-8859-7" }, |
162 | + {N_("Greek (Windows-1253)"), "windows-1253" }, |
163 | + {N_("Hebrew (IBM-862)"), "IBM862" }, |
164 | + {N_("Hebrew (Windows-1255)"), "windows-1255" }, |
165 | + {N_("Japanese (EUC-JP)"), "EUC-JP" }, |
166 | + {N_("Japanese (ISO-2022-JP)"), "ISO-2022-JP" }, |
167 | + {N_("Japanese (Shift_JIS)"), "Shift_JIS" }, |
168 | + {N_("Korean (EUC-KR)"), "EUC-KR" }, |
169 | + {N_("Nordic (ISO-8859-10)"), "ISO-8859-10" }, |
170 | + {N_("South European (ISO-8859-3)"), "ISO-8859-3" }, |
171 | + {N_("Thai (TIS-620)"), "TIS-620" }, |
172 | + {N_("Turkish (IBM-857)"), "IBM857" }, |
173 | + {N_("Turkish (ISO-8859-9)"), "ISO-8859-9" }, |
174 | + {N_("Turkish (Windows-1254)"), "windows-1254" }, |
175 | + {N_("Unicode (UTF-7)"), "UTF-7" }, |
176 | + {N_("Unicode (UTF-8)"), "UTF-8" }, |
177 | + {N_("Unicode (UTF-16BE)"), "UTF-16BE" }, |
178 | + {N_("Unicode (UTF-16LE)"), "UTF-16LE" }, |
179 | + {N_("Unicode (UTF-32BE)"), "UTF-32BE" }, |
180 | + {N_("Unicode (UTF-32LE)"), "UTF-32LE" }, |
181 | + {N_("Vietnamese (VISCII)"), "VISCII" }, |
182 | + {N_("Vietnamese (Windows-1258)"), "windows-1258" }, |
183 | + {N_("Visual Hebrew (ISO-8859-8)"), "ISO-8859-8" }, |
184 | + {N_("Western (IBM-850)"), "IBM850" }, |
185 | + {N_("Western (ISO-8859-1)"), "ISO-8859-1" }, |
186 | + {N_("Western (ISO-8859-15)"), "ISO-8859-15" }, |
187 | + {N_("Western (Windows-1252)"), "windows-1252" } |
188 | + |
189 | + /* |
190 | + * From this point, character sets aren't supported by iconv |
191 | + */ |
192 | +/* {N_("Arabic (IBM-864-I)"), "IBM864i" }, |
193 | + {N_("Arabic (ISO-8859-6-E)"), "ISO-8859-6-E" }, |
194 | + {N_("Arabic (ISO-8859-6-I)"), "ISO-8859-6-I" }, |
195 | + {N_("Arabic (MacArabic)"), "x-mac-arabic" }, |
196 | + {N_("Armenian (ARMSCII-8)"), "armscii-8" }, |
197 | + {N_("Central European (MacCE)"), "x-mac-ce" }, |
198 | + {N_("Chinese Simplified (GBK)"), "x-gbk" }, |
199 | + {N_("Chinese Simplified (HZ)"), "HZ-GB-2312" }, |
200 | + {N_("Chinese Traditional (EUC-TW)"), "x-euc-tw" }, |
201 | + {N_("Croatian (MacCroatian)"), "x-mac-croatian" }, |
202 | + {N_("Cyrillic (MacCyrillic)"), "x-mac-cyrillic" }, |
203 | + {N_("Cyrillic/Ukrainian (MacUkrainian)"), "x-mac-ukrainian" }, |
204 | + {N_("Farsi (MacFarsi)"), "x-mac-farsi"}, |
205 | + {N_("Greek (MacGreek)"), "x-mac-greek" }, |
206 | + {N_("Gujarati (MacGujarati)"), "x-mac-gujarati" }, |
207 | + {N_("Gurmukhi (MacGurmukhi)"), "x-mac-gurmukhi" }, |
208 | + {N_("Hebrew (ISO-8859-8-E)"), "ISO-8859-8-E" }, |
209 | + {N_("Hebrew (ISO-8859-8-I)"), "ISO-8859-8-I" }, |
210 | + {N_("Hebrew (MacHebrew)"), "x-mac-hebrew" }, |
211 | + {N_("Hindi (MacDevanagari)"), "x-mac-devanagari" }, |
212 | + {N_("Icelandic (MacIcelandic)"), "x-mac-icelandic" }, |
213 | + {N_("Korean (JOHAB)"), "x-johab" }, |
214 | + {N_("Korean (UHC)"), "x-windows-949" }, |
215 | + {N_("Romanian (MacRomanian)"), "x-mac-romanian" }, |
216 | + {N_("Turkish (MacTurkish)"), "x-mac-turkish" }, |
217 | + {N_("User Defined"), "x-user-defined" }, |
218 | + {N_("Vietnamese (TCVN)"), "x-viet-tcvn5712" }, |
219 | + {N_("Vietnamese (VPS)"), "x-viet-vps" }, |
220 | + {N_("Western (MacRoman)"), "x-mac-roman" }, |
221 | + // charsets whithout posibly translatable names |
222 | + {"T61.8bit", "T61.8bit" }, |
223 | + {"x-imap4-modified-utf7", "x-imap4-modified-utf7"}, |
224 | + {"x-u-escaped", "x-u-escaped" }, |
225 | + {"windows-936", "windows-936" } |
226 | +*/ |
227 | +}; |
228 | + |
229 | + |
230 | + |
231 | + |
232 | +/************* |
233 | + * Functions * |
234 | + *************/ |
235 | +// Return the last item of an doubly linked list |
236 | +static DLL * |
237 | +dll_last_c (DLL *list) |
238 | +{ |
239 | + DLL *item = list; |
240 | + |
241 | + while ( item->next ) |
242 | + item = item->next; |
243 | + |
244 | + return item; |
245 | +} |
246 | + |
247 | +// Append an item to the doubly linked list |
248 | +static DLL * |
249 | +dll_append_c (DLL *list, void *data) |
250 | +{ |
251 | + DLL *item = malloc (sizeof(DLL)); |
252 | + |
253 | + item->data = data; |
254 | + item->prev = dll_last_c(list); |
255 | + item->next = NULL; |
256 | + |
257 | + return item; |
258 | +} |
259 | + |
260 | +static char* get_current_charset (void) |
261 | +{ |
262 | + char *charset = getenv("CHARSET"); |
263 | + |
264 | +#ifdef HAVE_LANGINFO_CODESET |
265 | + if (!charset) |
266 | + charset = nl_langinfo(CODESET); |
267 | +#endif |
268 | + if (!charset) |
269 | + charset = "ISO-8859-1"; |
270 | + |
271 | + return charset; |
272 | +} |
273 | + |
274 | + |
275 | +#ifdef HAVE_ICONV_OPEN |
276 | +static char* convert_string (const char *string, char *from, char *to) |
277 | +{ |
278 | + size_t outleft, outsize, length; |
279 | + iconv_t cd; |
280 | + char *out, *outptr; |
281 | + const char *input = string; |
282 | + |
283 | + if (!string) |
284 | + return NULL; |
285 | + |
286 | + length = strlen(string); |
287 | + |
288 | + /* g_message("converting %s from %s to %s", string, from, to); */ |
289 | + if ((cd = iconv_open(to, from)) == (iconv_t)-1) |
290 | + { |
291 | + fprintf (stderr, "convert_string(): Conversion not supported. Charsets: %s -> %s", from, to); |
292 | + return strdup(string); |
293 | + } |
294 | + |
295 | + /* Due to a GLIBC bug, round outbuf_size up to a multiple of 4 */ |
296 | + /* + 1 for nul in case len == 1 */ |
297 | + outsize = ((length + 3) & ~3) + 1; |
298 | + out = g_malloc(outsize); |
299 | + outleft = outsize - 1; |
300 | + outptr = out; |
301 | + |
302 | + retry: |
303 | + if (iconv(cd, (char **)&input, &length, &outptr, &outleft) == -1) |
304 | + { |
305 | + int used; |
306 | + switch (errno) |
307 | + { |
308 | + case E2BIG: |
309 | + used = outptr - out; |
310 | + outsize = (outsize - 1) * 2 + 1; |
311 | + out = g_realloc(out, outsize); |
312 | + outptr = out + used; |
313 | + outleft = outsize - 1 - used; |
314 | + goto retry; |
315 | + case EINVAL: |
316 | + break; |
317 | + case EILSEQ: |
318 | + /* Invalid sequence, try to get the |
319 | + rest of the string */ |
320 | + input++; |
321 | + length = strlen(input); |
322 | + goto retry; |
323 | + default: |
324 | + fprintf (stderr, "convert_string(): Conversion failed. Inputstring: %s; Error: %s", string, strerror(errno)); |
325 | + break; |
326 | + } |
327 | + } |
328 | + *outptr = '\0'; |
329 | + |
330 | + iconv_close(cd); |
331 | + return out; |
332 | +} |
333 | +#else |
334 | +static char* convert_string (const char *string, char *from, char *to) |
335 | +{ |
336 | + if (!string) |
337 | + return NULL; |
338 | + return strdup(string); |
339 | +} |
340 | +#endif |
341 | + |
342 | + |
343 | +/* |
344 | + * Conversion with UTF-8 for ogg tags |
345 | + */ |
346 | +char* convert_to_utf8 (const char *string) |
347 | +{ |
348 | + char *charset = get_current_charset(); |
349 | + |
350 | + return convert_string(string, charset, "UTF-8"); |
351 | +} |
352 | + |
353 | +char* convert_from_utf8 (const char *string) |
354 | +{ |
355 | + char *charset = get_current_charset(); |
356 | + |
357 | + return convert_string(string, "UTF-8", charset); |
358 | +} |
359 | + |
360 | + |
361 | +DLL *Charset_Create_List (void) |
362 | +{ |
363 | + DLL *list = NULL; |
364 | + int i; |
365 | + |
366 | + for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++) |
367 | + list = dll_append_c (list,_(charset_trans_array[i].charset_title)); |
368 | + return list; |
369 | +} |
370 | + |
371 | + |
372 | +/* |
373 | + * Return charset_name from charset_title |
374 | + */ |
375 | +char *Charset_Get_Name_From_Title (char *charset_title) |
376 | +{ |
377 | + int i; |
378 | + |
379 | + if (charset_title) |
380 | + for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++) |
381 | + if ( strcasecmp(_(charset_title),_(charset_trans_array[i].charset_title)) == 0 ) |
382 | + return charset_trans_array[i].charset_name; |
383 | + return ""; |
384 | +} |
385 | + |
386 | + |
387 | +/* |
388 | + * Return charset_title from charset_name |
389 | + */ |
390 | +char *Charset_Get_Title_From_Name (char *charset_name) |
391 | +{ |
392 | + int i; |
393 | + |
394 | + if (charset_name) |
395 | + for (i=0; i<CHARSET_TRANS_ARRAY_LEN; i++) |
396 | + if ( strcasecmp(charset_name,charset_trans_array[i].charset_name) == 0 ) |
397 | + return _(charset_trans_array[i].charset_title); |
398 | + return ""; |
399 | +} |
400 | + |
401 | + |
402 | + |
403 | +/* |
404 | + * Test if the conversion is supported between two character sets ('from' and 'to) |
405 | + */ |
406 | +#ifdef HAVE_ICONV_OPEN |
407 | +short int test_conversion_charset (char *from, char *to) |
408 | +{ |
409 | + iconv_t cd; |
410 | + |
411 | + if ((cd=iconv_open(to,from)) == (iconv_t)-1) |
412 | + { |
413 | + /* Conversion not supported */ |
414 | + return FALSE; |
415 | + } |
416 | + iconv_close(cd); |
417 | + return TRUE; |
418 | +} |
419 | +#else |
420 | +short int test_conversion_charset (char *from, char *to) |
421 | +{ |
422 | + return TRUE; |
423 | +} |
424 | +#endif |
425 | diff -Naur xmms-1.2.9-orig/Input/mpg123/fileinfo.c xmms-1.2.9/Input/mpg123/fileinfo.c |
426 | --- xmms-1.2.9-orig/Input/mpg123/fileinfo.c Thu Jan 29 06:43:24 2004 |
427 | +++ xmms-1.2.9/Input/mpg123/fileinfo.c Thu Jan 29 06:39:47 2004 |
428 | @@ -25,28 +25,36 @@ |
429 | #include <errno.h> |
430 | #include <libxmms/xentry.h> |
431 | #include "mpg123.h" |
432 | +#include "lib_id3v2.h" |
433 | + |
434 | +#define MAX_STR_LEN 100 |
435 | +#define MAX_ENTRY_LEN2 1023 |
436 | |
437 | static GtkWidget *window = NULL; |
438 | -static GtkWidget *filename_entry, *id3_frame; |
439 | -static GtkWidget *title_entry, *artist_entry, *album_entry, *year_entry; |
440 | -static GtkWidget *tracknum_entry, *comment_entry, *genre_combo; |
441 | +static GtkWidget *notebook = NULL; |
442 | +static GtkWidget *filename_entry, *id3v1_frame, *id3v2_frame; |
443 | +static GtkWidget *v1_checkbox, *v2_checkbox; |
444 | +static GtkWidget *v1_title_entry, *v1_artist_entry, *v1_album_entry, *v1_year_entry, *v1_tracknum_entry, *v1_comment_entry; |
445 | +static GtkWidget *v2_title_entry, *v2_artist_entry, *v2_album_entry, *v2_year_entry, *v2_tracknum_entry, *v2_comment_entry, |
446 | + *v2_composer_entry, *v2_orig_artist_entry, *v2_url_entry, *v2_encoded_by_entry; |
447 | +static GtkWidget *v1_genre_combo, *v2_genre_combo; |
448 | static GtkWidget *mpeg_level, *mpeg_bitrate, *mpeg_samplerate, *mpeg_flags; |
449 | static GtkWidget *mpeg_fileinfo; |
450 | |
451 | +static GPtrArray *v1_labels_list = NULL, *v2_labels_list = NULL; // TODO: Where will these be freed? |
452 | static GList *genre_list; |
453 | struct genre_item { |
454 | const char *name; |
455 | int id; |
456 | }; |
457 | -static int current_genre; |
458 | +static int v1_current_genre; |
459 | +static int v2_current_genre; |
460 | static char *current_filename; |
461 | |
462 | extern char *mpg123_filename; |
463 | extern int mpg123_bitrate, mpg123_frequency, mpg123_layer, mpg123_lsf, mpg123_mode; |
464 | extern gboolean mpg123_stereo, mpg123_mpeg25; |
465 | |
466 | -#define MAX_STR_LEN 100 |
467 | - |
468 | static void label_set_text(GtkWidget * label, char *str, ...) |
469 | G_GNUC_PRINTF(2, 3); |
470 | |
471 | @@ -66,6 +74,12 @@ |
472 | strncpy(tag, gtk_entry_get_text(entry), length); |
473 | } |
474 | |
475 | +void copy_entry_tag(GtkEntry * src, GtkEntry * dest, int length) |
476 | +{ |
477 | + set_entry_tag(dest, gtk_entry_get_text(src), length); |
478 | + return; |
479 | +} |
480 | + |
481 | static int genre_find_index(GList *genre_list, int id) |
482 | { |
483 | int idx = 0; |
484 | @@ -80,15 +94,29 @@ |
485 | return idx; |
486 | } |
487 | |
488 | +static int genre_find_index_str(GList *genre_list, const char* str) |
489 | +{ |
490 | + int idx = 0; |
491 | + while (genre_list) |
492 | + { |
493 | + struct genre_item *item = genre_list->data; |
494 | + if (strcmp(item->name, str) == 0) |
495 | + break; |
496 | + idx++; |
497 | + genre_list = genre_list->next; |
498 | + } |
499 | + return idx; |
500 | +} |
501 | + |
502 | static int genre_comp_func(gconstpointer a, gconstpointer b) |
503 | { |
504 | const struct genre_item *ga = a, *gb = b; |
505 | return strcasecmp(ga->name, gb->name); |
506 | } |
507 | |
508 | -static void save_cb(GtkWidget * w, gpointer data) |
509 | +static void remove_id3v1(void) |
510 | { |
511 | - int fd; |
512 | + int fd, len; |
513 | struct id3v1tag_t tag; |
514 | char *msg = NULL; |
515 | |
516 | @@ -97,71 +125,36 @@ |
517 | |
518 | if ((fd = open(current_filename, O_RDWR)) != -1) |
519 | { |
520 | - int tracknum; |
521 | - |
522 | - lseek(fd, -128, SEEK_END); |
523 | + len = lseek(fd, -128, SEEK_END); |
524 | read(fd, &tag, sizeof (struct id3v1tag_t)); |
525 | |
526 | if (!strncmp(tag.tag, "TAG", 3)) |
527 | - lseek(fd, -128, SEEK_END); |
528 | - else |
529 | - lseek(fd, 0, SEEK_END); |
530 | - tag.tag[0] = 'T'; |
531 | - tag.tag[1] = 'A'; |
532 | - tag.tag[2] = 'G'; |
533 | - get_entry_tag(GTK_ENTRY(title_entry), tag.title, 30); |
534 | - get_entry_tag(GTK_ENTRY(artist_entry), tag.artist, 30); |
535 | - get_entry_tag(GTK_ENTRY(album_entry), tag.album, 30); |
536 | - get_entry_tag(GTK_ENTRY(year_entry), tag.year, 4); |
537 | - tracknum = atoi(gtk_entry_get_text(GTK_ENTRY(tracknum_entry))); |
538 | - if (tracknum > 0) |
539 | { |
540 | - get_entry_tag(GTK_ENTRY(comment_entry), |
541 | - tag.u.v1_1.comment, 28); |
542 | - tag.u.v1_1.__zero = 0; |
543 | - tag.u.v1_1.track_number = MIN(tracknum, 255); |
544 | + if (ftruncate(fd, len)) |
545 | + msg = g_strdup_printf(_("%s\n" |
546 | + "Unable to truncate file: %s"), |
547 | + _("Couldn't remove tag!"), |
548 | + strerror(errno)); |
549 | } |
550 | - else |
551 | - get_entry_tag(GTK_ENTRY(comment_entry), |
552 | - tag.u.v1_0.comment, 30); |
553 | - tag.genre = current_genre; |
554 | - if (write(fd, &tag, sizeof (tag)) != sizeof (tag)) |
555 | - msg = g_strdup_printf(_("%s\nUnable to write to file: %s"), |
556 | - _("Couldn't write tag!"), |
557 | - strerror(errno)); |
558 | close(fd); |
559 | } |
560 | else |
561 | msg = g_strdup_printf(_("%s\nUnable to open file: %s"), |
562 | - _("Couldn't write tag!"), |
563 | + _("Couldn't remove tag!"), |
564 | strerror(errno)); |
565 | if (msg) |
566 | { |
567 | - GtkWidget *mwin = xmms_show_message(_("File Info"), msg, |
568 | - _("Ok"), FALSE, NULL, NULL); |
569 | + GtkWidget *mwin = xmms_show_message(_("File Info"), msg, _("Ok"), |
570 | + FALSE, NULL, NULL); |
571 | gtk_window_set_transient_for(GTK_WINDOW(mwin), |
572 | GTK_WINDOW(window)); |
573 | g_free(msg); |
574 | } |
575 | - else |
576 | - gtk_widget_destroy(window); |
577 | -} |
578 | - |
579 | -static void label_set_text(GtkWidget * label, char *str, ...) |
580 | -{ |
581 | - va_list args; |
582 | - char tempstr[MAX_STR_LEN]; |
583 | - |
584 | - va_start(args, str); |
585 | - g_vsnprintf(tempstr, MAX_STR_LEN, str, args); |
586 | - va_end(args); |
587 | - |
588 | - gtk_label_set_text(GTK_LABEL(label), tempstr); |
589 | } |
590 | |
591 | -static void remove_id3_cb(GtkWidget * w, gpointer data) |
592 | +static void save_cb(GtkWidget * w, gpointer data) |
593 | { |
594 | - int fd, len; |
595 | + int fd; |
596 | struct id3v1tag_t tag; |
597 | char *msg = NULL; |
598 | |
599 | @@ -170,36 +163,95 @@ |
600 | |
601 | if ((fd = open(current_filename, O_RDWR)) != -1) |
602 | { |
603 | - len = lseek(fd, -128, SEEK_END); |
604 | - read(fd, &tag, sizeof (struct id3v1tag_t)); |
605 | + if (!GTK_TOGGLE_BUTTON(v1_checkbox)->active) { |
606 | + // Try to save id3v1 tag |
607 | + int tracknum; |
608 | |
609 | - if (!strncmp(tag.tag, "TAG", 3)) |
610 | - { |
611 | - if (ftruncate(fd, len)) |
612 | - msg = g_strdup_printf( |
613 | - _("%s\n" |
614 | - "Unable to truncate file: %s"), |
615 | - _("Couldn't remove tag!"), |
616 | - strerror(errno)); |
617 | + lseek(fd, -128, SEEK_END); |
618 | + read(fd, &tag, sizeof (struct id3v1tag_t)); |
619 | + |
620 | + if (!strncmp(tag.tag, "TAG", 3)) |
621 | + lseek(fd, -128, SEEK_END); |
622 | + else |
623 | + lseek(fd, 0, SEEK_END); |
624 | + tag.tag[0] = 'T'; |
625 | + tag.tag[1] = 'A'; |
626 | + tag.tag[2] = 'G'; |
627 | + get_entry_tag(GTK_ENTRY(v1_title_entry), tag.title, 30); |
628 | + get_entry_tag(GTK_ENTRY(v1_artist_entry), tag.artist, 30); |
629 | + get_entry_tag(GTK_ENTRY(v1_album_entry), tag.album, 30); |
630 | + get_entry_tag(GTK_ENTRY(v1_year_entry), tag.year, 4); |
631 | + tracknum = atoi(gtk_entry_get_text(GTK_ENTRY(v1_tracknum_entry))); |
632 | + if (tracknum > 0) |
633 | + { |
634 | + get_entry_tag(GTK_ENTRY(v1_comment_entry), |
635 | + tag.u.v1_1.comment, 28); |
636 | + tag.u.v1_1.__zero = 0; |
637 | + tag.u.v1_1.track_number = MIN(tracknum, 255); |
638 | + } |
639 | + else |
640 | + get_entry_tag(GTK_ENTRY(v1_comment_entry), |
641 | + tag.u.v1_0.comment, 30); |
642 | + tag.genre = v1_current_genre; |
643 | + if (write(fd, &tag, sizeof (tag)) != sizeof (tag)) |
644 | + msg = g_strdup_printf(_("%s\nUnable to write to file: %s"), |
645 | + _("Couldn't write tag!"), |
646 | + strerror(errno)); |
647 | + } else { |
648 | + // Remove the id3v1 tag from the file |
649 | + remove_id3v1(); |
650 | } |
651 | - else |
652 | - msg = strdup(_("No tag to remove!")); |
653 | - close(fd); |
654 | + |
655 | + if (!GTK_TOGGLE_BUTTON(v2_checkbox)->active) { |
656 | + |
657 | + id3Tag v2_tag; |
658 | + strncpy(v2_tag.title, gtk_entry_get_text(GTK_ENTRY(v2_title_entry)), MAX_ENTRY_LEN2); |
659 | + strncpy(v2_tag.artist, gtk_entry_get_text(GTK_ENTRY(v2_artist_entry)), MAX_ENTRY_LEN2); |
660 | + strncpy(v2_tag.album, gtk_entry_get_text(GTK_ENTRY(v2_album_entry)), MAX_ENTRY_LEN2); |
661 | + strncpy(v2_tag.year, gtk_entry_get_text(GTK_ENTRY(v2_year_entry)), 4); |
662 | + strncpy(v2_tag.comment, gtk_entry_get_text(GTK_ENTRY(v2_comment_entry)), MAX_ENTRY_LEN2); |
663 | + strncpy(v2_tag.track, gtk_entry_get_text(GTK_ENTRY(v2_tracknum_entry)), 3); |
664 | + snprintf(v2_tag.genre, 6, "(%d)", v2_current_genre); |
665 | + |
666 | + strncpy(v2_tag.composer, gtk_entry_get_text(GTK_ENTRY(v2_composer_entry)), MAX_ENTRY_LEN2); |
667 | + strncpy(v2_tag.url, gtk_entry_get_text(GTK_ENTRY(v2_url_entry)), MAX_ENTRY_LEN2); |
668 | + strncpy(v2_tag.orig_artist, gtk_entry_get_text(GTK_ENTRY(v2_orig_artist_entry)), MAX_ENTRY_LEN2); |
669 | + strncpy(v2_tag.enc_by, gtk_entry_get_text(GTK_ENTRY(v2_encoded_by_entry)), MAX_ENTRY_LEN2); |
670 | + |
671 | + set_id3v2_tag(&v2_tag, current_filename); |
672 | + |
673 | + } else { |
674 | + // remove the id3v2 tag from the file |
675 | + del_id3v2_tag(current_filename); |
676 | + } |
677 | + |
678 | + if (fd) |
679 | + close(fd); |
680 | } |
681 | else |
682 | msg = g_strdup_printf(_("%s\nUnable to open file: %s"), |
683 | - _("Couldn't remove tag!"), |
684 | + _("Couldn't write tag!"), |
685 | strerror(errno)); |
686 | if (msg) |
687 | { |
688 | - GtkWidget *mwin = xmms_show_message(_("File Info"), msg, |
689 | - _("Ok"), FALSE, NULL, NULL); |
690 | + GtkWidget *mwin = xmms_show_message(_("File Info"), msg, _("Ok"), |
691 | + FALSE, NULL, NULL); |
692 | gtk_window_set_transient_for(GTK_WINDOW(mwin), |
693 | GTK_WINDOW(window)); |
694 | g_free(msg); |
695 | } |
696 | - else |
697 | - gtk_widget_destroy(window); |
698 | +} |
699 | + |
700 | +static void label_set_text(GtkWidget * label, char *str, ...) |
701 | +{ |
702 | + va_list args; |
703 | + char tempstr[MAX_STR_LEN]; |
704 | + |
705 | + va_start(args, str); |
706 | + g_vsnprintf(tempstr, MAX_STR_LEN, str, args); |
707 | + va_end(args); |
708 | + |
709 | + gtk_label_set_text(GTK_LABEL(label), tempstr); |
710 | } |
711 | |
712 | static void set_mpeg_level_label(gboolean mpeg25, int lsf, int layer) |
713 | @@ -222,28 +274,144 @@ |
714 | |
715 | static void file_info_http(char *filename) |
716 | { |
717 | - gtk_widget_set_sensitive(id3_frame, FALSE); |
718 | + gtk_widget_set_sensitive(id3v1_frame, FALSE); |
719 | + gtk_widget_set_sensitive(id3v2_frame, FALSE); |
720 | if (mpg123_filename && !strcmp(filename, mpg123_filename) && |
721 | mpg123_bitrate != 0) |
722 | { |
723 | - set_mpeg_level_label(mpg123_mpeg25, mpg123_lsf, mpg123_layer); |
724 | + set_mpeg_level_label(mpg123_mpeg25, mpg123_lsf, |
725 | + mpg123_layer); |
726 | label_set_text(mpeg_bitrate, _("Bitrate: %d kb/s"), |
727 | - mpg123_bitrate); |
728 | + mpg123_bitrate); |
729 | label_set_text(mpeg_samplerate, _("Samplerate: %d Hz"), |
730 | - mpg123_frequency); |
731 | + mpg123_frequency); |
732 | label_set_text(mpeg_flags, "%s", |
733 | - channel_mode_name(mpg123_mode)); |
734 | + channel_mode_name(mpg123_mode)); |
735 | } |
736 | } |
737 | |
738 | -static void genre_selected(GtkList *list, GtkWidget *w, gpointer data) |
739 | +void copy_v2_to_v1_cb(GtkButton *button, gpointer user_data) |
740 | +{ |
741 | + copy_entry_tag(GTK_ENTRY(v2_title_entry), GTK_ENTRY(v1_title_entry), 30); |
742 | + copy_entry_tag(GTK_ENTRY(v2_artist_entry), GTK_ENTRY(v1_artist_entry), 30); |
743 | + copy_entry_tag(GTK_ENTRY(v2_album_entry), GTK_ENTRY(v1_album_entry), 30); |
744 | + copy_entry_tag(GTK_ENTRY(v2_year_entry), GTK_ENTRY(v1_year_entry), 4); |
745 | + copy_entry_tag(GTK_ENTRY(v2_comment_entry), GTK_ENTRY(v1_comment_entry), 30); |
746 | + copy_entry_tag(GTK_ENTRY(v2_tracknum_entry), GTK_ENTRY(v1_tracknum_entry), 3); |
747 | + |
748 | + gtk_list_select_item(GTK_LIST(GTK_COMBO(v1_genre_combo)->list), genre_find_index(genre_list, v2_current_genre)); |
749 | + return; |
750 | +} |
751 | + |
752 | +void copy_v1_to_v2_cb(GtkButton *button, gpointer user_data) |
753 | +{ |
754 | + copy_entry_tag(GTK_ENTRY(v1_title_entry), GTK_ENTRY(v2_title_entry), MAX_ENTRY_LEN2); |
755 | + copy_entry_tag(GTK_ENTRY(v1_artist_entry), GTK_ENTRY(v2_artist_entry), MAX_ENTRY_LEN2); |
756 | + copy_entry_tag(GTK_ENTRY(v1_album_entry), GTK_ENTRY(v2_album_entry), MAX_ENTRY_LEN2); |
757 | + copy_entry_tag(GTK_ENTRY(v1_year_entry), GTK_ENTRY(v2_year_entry), 4); |
758 | + copy_entry_tag(GTK_ENTRY(v1_comment_entry), GTK_ENTRY(v2_comment_entry), MAX_ENTRY_LEN2); |
759 | + copy_entry_tag(GTK_ENTRY(v1_tracknum_entry), GTK_ENTRY(v2_tracknum_entry), 3); |
760 | + |
761 | + gtk_list_select_item(GTK_LIST(GTK_COMBO(v2_genre_combo)->list), genre_find_index(genre_list, v1_current_genre)); |
762 | + //int genreID = find_genre_id(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(v1_genre_combo)->entry))); |
763 | + //gtk_list_select_item(GTK_LIST(GTK_COMBO(v2_genre_combo)->list), |
764 | + // g_list_index(genre_list, (char *) mpg123_id3_genres[genreID])); |
765 | + return; |
766 | +} |
767 | + |
768 | +void v1_toggle_cb (GtkWidget *widget, gpointer data) |
769 | +{ |
770 | + int i = 0; |
771 | + if (GTK_TOGGLE_BUTTON (widget)->active) |
772 | + { |
773 | + // If control reaches here, the toggle button is down |
774 | + // Gray out labels |
775 | + for (i = 0; i < v1_labels_list->len; i++) { |
776 | + gtk_widget_set_sensitive(GTK_WIDGET( g_ptr_array_index(v1_labels_list, i) ), FALSE); |
777 | + } |
778 | + gtk_widget_set_sensitive(v1_title_entry, FALSE); |
779 | + gtk_widget_set_sensitive(v1_artist_entry, FALSE); |
780 | + gtk_widget_set_sensitive(v1_album_entry, FALSE); |
781 | + gtk_widget_set_sensitive(v1_year_entry, FALSE); |
782 | + gtk_widget_set_sensitive(v1_tracknum_entry, FALSE); |
783 | + gtk_widget_set_sensitive(v1_comment_entry, FALSE); |
784 | + gtk_widget_set_sensitive(v1_genre_combo, FALSE); |
785 | + } else { |
786 | + |
787 | + // If control reaches here, the toggle button is up |
788 | + // Enable labels |
789 | + for (i = 0; i < v1_labels_list->len; i++) { |
790 | + gtk_widget_set_sensitive(GTK_WIDGET( g_ptr_array_index(v1_labels_list, i) ), TRUE); |
791 | + } |
792 | + gtk_widget_set_sensitive(v1_title_entry, TRUE); |
793 | + gtk_widget_set_sensitive(v1_artist_entry, TRUE); |
794 | + gtk_widget_set_sensitive(v1_album_entry, TRUE); |
795 | + gtk_widget_set_sensitive(v1_year_entry, TRUE); |
796 | + gtk_widget_set_sensitive(v1_tracknum_entry, TRUE); |
797 | + gtk_widget_set_sensitive(v1_comment_entry, TRUE); |
798 | + gtk_widget_set_sensitive(v1_genre_combo, TRUE); |
799 | + } |
800 | +} |
801 | + |
802 | +void v2_toggle_cb (GtkWidget *widget, gpointer data) |
803 | +{ |
804 | + int i = 0; |
805 | + if (GTK_TOGGLE_BUTTON (widget)->active) |
806 | + { |
807 | + // If control reaches here, the toggle button is down |
808 | + // Gray out labels |
809 | + for (i = 0; i < v2_labels_list->len; i++) { |
810 | + gtk_widget_set_sensitive(GTK_WIDGET( g_ptr_array_index(v2_labels_list, i) ), FALSE); |
811 | + } |
812 | + gtk_widget_set_sensitive(v2_title_entry, FALSE); |
813 | + gtk_widget_set_sensitive(v2_artist_entry, FALSE); |
814 | + gtk_widget_set_sensitive(v2_album_entry, FALSE); |
815 | + gtk_widget_set_sensitive(v2_year_entry, FALSE); |
816 | + gtk_widget_set_sensitive(v2_tracknum_entry, FALSE); |
817 | + gtk_widget_set_sensitive(v2_comment_entry, FALSE); |
818 | + gtk_widget_set_sensitive(v2_composer_entry, FALSE); |
819 | + gtk_widget_set_sensitive(v2_orig_artist_entry, FALSE); |
820 | + gtk_widget_set_sensitive(v2_url_entry, FALSE); |
821 | + gtk_widget_set_sensitive(v2_encoded_by_entry, FALSE); |
822 | + gtk_widget_set_sensitive(v2_genre_combo, FALSE); |
823 | + } else { |
824 | + |
825 | + // If control reaches here, the toggle button is up |
826 | + // Enable labels |
827 | + for (i = 0; i < v2_labels_list->len; i++) { |
828 | + gtk_widget_set_sensitive(GTK_WIDGET( g_ptr_array_index(v2_labels_list, i) ), TRUE); |
829 | + } |
830 | + gtk_widget_set_sensitive(v2_title_entry, TRUE); |
831 | + gtk_widget_set_sensitive(v2_artist_entry, TRUE); |
832 | + gtk_widget_set_sensitive(v2_album_entry, TRUE); |
833 | + gtk_widget_set_sensitive(v2_year_entry, TRUE); |
834 | + gtk_widget_set_sensitive(v2_tracknum_entry, TRUE); |
835 | + gtk_widget_set_sensitive(v2_comment_entry, TRUE); |
836 | + gtk_widget_set_sensitive(v2_composer_entry, TRUE); |
837 | + gtk_widget_set_sensitive(v2_orig_artist_entry, TRUE); |
838 | + gtk_widget_set_sensitive(v2_url_entry, TRUE); |
839 | + gtk_widget_set_sensitive(v2_encoded_by_entry, TRUE); |
840 | + gtk_widget_set_sensitive(v2_genre_combo, TRUE); |
841 | + } |
842 | +} |
843 | +static void v1_genre_selected(GtkList *list, GtkWidget *w, gpointer data) |
844 | +{ |
845 | + void * p; |
846 | + p = gtk_object_get_data(GTK_OBJECT(w), "genre_id"); |
847 | + if (p != NULL) |
848 | + v1_current_genre = GPOINTER_TO_INT(p); |
849 | + else |
850 | + v1_current_genre = 0; |
851 | +} |
852 | + |
853 | +static void v2_genre_selected(GtkList *list, GtkWidget *w, gpointer data) |
854 | { |
855 | void * p; |
856 | p = gtk_object_get_data(GTK_OBJECT(w), "genre_id"); |
857 | if (p != NULL) |
858 | - current_genre = GPOINTER_TO_INT(p); |
859 | + v2_current_genre = GPOINTER_TO_INT(p); |
860 | else |
861 | - current_genre = 0; |
862 | + v2_current_genre = 0; |
863 | } |
864 | |
865 | static void genre_set_popdown(GtkWidget *combo, GList *genres) |
866 | @@ -266,11 +434,12 @@ |
867 | void mpg123_file_info_box(char *filename) |
868 | { |
869 | int i; |
870 | - struct id3v1tag_t tag; |
871 | + struct id3v1tag_t id3v1tag; |
872 | FILE *fh; |
873 | char *tmp, *title; |
874 | const char *emphasis[4]; |
875 | const char *bool_label[2]; |
876 | + struct id3tag_t id3v2tag; |
877 | |
878 | emphasis[0] = _("None"); |
879 | emphasis[1] = _("50/15 ms"); |
880 | @@ -281,116 +450,123 @@ |
881 | |
882 | if (!window) |
883 | { |
884 | - GtkWidget *vbox, *hbox, *left_vbox, *table; |
885 | - GtkWidget *mpeg_frame, *mpeg_box; |
886 | - GtkWidget *label, *filename_hbox; |
887 | - GtkWidget *bbox, *save, *remove_id3, *cancel; |
888 | - |
889 | - window = gtk_window_new(GTK_WINDOW_DIALOG); |
890 | - gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE); |
891 | - gtk_signal_connect(GTK_OBJECT(window), "destroy", |
892 | - gtk_widget_destroyed, &window); |
893 | - gtk_container_set_border_width(GTK_CONTAINER(window), 10); |
894 | - |
895 | - vbox = gtk_vbox_new(FALSE, 10); |
896 | - gtk_container_add(GTK_CONTAINER(window), vbox); |
897 | + GtkWidget *window_vbox, |
898 | + *id3v1_vbox, *id3v2_vbox, *id3v1_frame_vbox, *id3v2_frame_vbox, |
899 | + *mpeg_lvbox, *mpeg_rvbox, *mpeg_hbox, *mpeg_box, *mpeg_frame, |
900 | + *bbox, *save, *close, *copy_to, *copy_from, |
901 | + *table, *label, *filename_hbox; |
902 | + |
903 | + v1_labels_list = g_ptr_array_new(); |
904 | + v2_labels_list = g_ptr_array_new(); |
905 | + |
906 | + window = gtk_window_new(GTK_WINDOW_DIALOG); |
907 | + //gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE); |
908 | + gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &window); |
909 | + gtk_container_set_border_width(GTK_CONTAINER(window), 10); |
910 | |
911 | + window_vbox = gtk_vbox_new(FALSE,10); |
912 | filename_hbox = gtk_hbox_new(FALSE, 5); |
913 | - gtk_box_pack_start(GTK_BOX(vbox), filename_hbox, |
914 | - FALSE, TRUE, 0); |
915 | + gtk_box_pack_start(GTK_BOX(window_vbox), filename_hbox, FALSE, TRUE, 0); |
916 | |
917 | label = gtk_label_new(_("Filename:")); |
918 | - gtk_box_pack_start(GTK_BOX(filename_hbox), label, |
919 | - FALSE, TRUE, 0); |
920 | + gtk_box_pack_start(GTK_BOX(filename_hbox), label, FALSE, TRUE, 0); |
921 | filename_entry = xmms_entry_new(); |
922 | gtk_editable_set_editable(GTK_EDITABLE(filename_entry), FALSE); |
923 | - gtk_box_pack_start(GTK_BOX(filename_hbox), |
924 | - filename_entry, TRUE, TRUE, 0); |
925 | - |
926 | - hbox = gtk_hbox_new(FALSE, 10); |
927 | - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); |
928 | - |
929 | - left_vbox = gtk_vbox_new(FALSE, 10); |
930 | - gtk_box_pack_start(GTK_BOX(hbox), left_vbox, FALSE, FALSE, 0); |
931 | - |
932 | - id3_frame = gtk_frame_new(_("ID3 Tag:")); |
933 | - gtk_box_pack_start(GTK_BOX(left_vbox), id3_frame, |
934 | - FALSE, FALSE, 0); |
935 | - |
936 | - table = gtk_table_new(5, 5, FALSE); |
937 | - gtk_container_set_border_width(GTK_CONTAINER(table), 5); |
938 | - gtk_container_add(GTK_CONTAINER(id3_frame), table); |
939 | - |
940 | - label = gtk_label_new(_("Title:")); |
941 | - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
942 | - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, |
943 | - GTK_FILL, GTK_FILL, 5, 5); |
944 | - |
945 | - title_entry = gtk_entry_new_with_max_length(30); |
946 | - gtk_table_attach(GTK_TABLE(table), title_entry, 1, 4, 0, 1, |
947 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
948 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); |
949 | - |
950 | - label = gtk_label_new(_("Artist:")); |
951 | - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
952 | - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, |
953 | - GTK_FILL, GTK_FILL, 5, 5); |
954 | - |
955 | - artist_entry = gtk_entry_new_with_max_length(30); |
956 | - gtk_table_attach(GTK_TABLE(table), artist_entry, 1, 4, 1, 2, |
957 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
958 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); |
959 | - |
960 | - label = gtk_label_new(_("Album:")); |
961 | - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
962 | - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, |
963 | - GTK_FILL, GTK_FILL, 5, 5); |
964 | - |
965 | - album_entry = gtk_entry_new_with_max_length(30); |
966 | - gtk_table_attach(GTK_TABLE(table), album_entry, 1, 4, 2, 3, |
967 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
968 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); |
969 | - |
970 | - label = gtk_label_new(_("Comment:")); |
971 | - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
972 | - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, |
973 | - GTK_FILL, GTK_FILL, 5, 5); |
974 | - |
975 | - comment_entry = gtk_entry_new_with_max_length(30); |
976 | - gtk_table_attach(GTK_TABLE(table), comment_entry, 1, 4, 3, 4, |
977 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
978 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); |
979 | - |
980 | - label = gtk_label_new(_("Year:")); |
981 | - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
982 | - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, |
983 | - GTK_FILL, GTK_FILL, 5, 5); |
984 | - |
985 | - year_entry = gtk_entry_new_with_max_length(4); |
986 | - gtk_widget_set_usize(year_entry, 40, -1); |
987 | - gtk_table_attach(GTK_TABLE(table), year_entry, 1, 2, 4, 5, |
988 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
989 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); |
990 | - |
991 | - label = gtk_label_new(_("Track number:")); |
992 | - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
993 | - gtk_table_attach(GTK_TABLE(table), label, 2, 3, 4, 5, |
994 | - GTK_FILL, GTK_FILL, 5, 5); |
995 | - |
996 | - tracknum_entry = gtk_entry_new_with_max_length(3); |
997 | - gtk_widget_set_usize(tracknum_entry, 40, -1); |
998 | - gtk_table_attach(GTK_TABLE(table), tracknum_entry, 3, 4, 4, 5, |
999 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1000 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); |
1001 | - |
1002 | - label = gtk_label_new(_("Genre:")); |
1003 | - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1004 | - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 5, 6, |
1005 | - GTK_FILL, GTK_FILL, 5, 5); |
1006 | - |
1007 | - genre_combo = gtk_combo_new(); |
1008 | - gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), |
1009 | - FALSE); |
1010 | + gtk_box_pack_start(GTK_BOX(filename_hbox), filename_entry, TRUE, TRUE, 0); |
1011 | + |
1012 | + id3v1_vbox = gtk_vbox_new(FALSE, 10); |
1013 | + id3v1_frame = gtk_frame_new("ID3v1 Information"); |
1014 | + gtk_box_pack_start(GTK_BOX(id3v1_vbox), id3v1_frame, TRUE, TRUE, 0); |
1015 | + |
1016 | + id3v1_frame_vbox = gtk_vbox_new(FALSE,10); |
1017 | + gtk_container_add(GTK_CONTAINER(id3v1_frame), id3v1_frame_vbox); |
1018 | + |
1019 | + table = gtk_table_new(6, 6, FALSE); |
1020 | + gtk_container_set_border_width(GTK_CONTAINER(table), 5); |
1021 | + //gtk_widget_set_usize(GTK_WIDGET(table), 325, -1); |
1022 | + //gtk_container_add(GTK_CONTAINER(id3v1_frame), table); |
1023 | + gtk_box_pack_start(GTK_BOX(id3v1_frame_vbox), table, FALSE, FALSE, 0); |
1024 | + |
1025 | + v1_checkbox = gtk_check_button_new_with_label ("Disable ID3v1 Tag"); |
1026 | + gtk_signal_connect(GTK_OBJECT(v1_checkbox), "toggled", GTK_SIGNAL_FUNC(v1_toggle_cb), NULL); |
1027 | + gtk_table_attach(GTK_TABLE(table), v1_checkbox, 1, 3, 0, 1, |
1028 | + GTK_FILL, GTK_FILL, 0, 2); |
1029 | + |
1030 | + label = gtk_label_new("Track number:"); |
1031 | + g_ptr_array_add(v1_labels_list, (gpointer)label); |
1032 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1033 | + gtk_table_attach(GTK_TABLE(table), label, 3, 4, 0, 1, |
1034 | + GTK_FILL, GTK_FILL, 5,5); |
1035 | + |
1036 | + v1_tracknum_entry = gtk_entry_new_with_max_length(3); |
1037 | + gtk_widget_set_usize(v1_tracknum_entry, 20, -1); |
1038 | + gtk_table_attach(GTK_TABLE(table), v1_tracknum_entry, 4, 5, 0, 1, |
1039 | + GTK_FILL, GTK_FILL, 0, 2); |
1040 | + |
1041 | + label = gtk_label_new("Title:"); |
1042 | + g_ptr_array_add(v1_labels_list, (gpointer)label); |
1043 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1044 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, |
1045 | + GTK_FILL, GTK_FILL, 5, 5); |
1046 | + |
1047 | + v1_title_entry = gtk_entry_new_with_max_length(30); |
1048 | + gtk_table_attach(GTK_TABLE(table), v1_title_entry, 1, 5, 1, 2, |
1049 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1050 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 2); |
1051 | + |
1052 | + label = gtk_label_new("Artist:"); |
1053 | + g_ptr_array_add(v1_labels_list, (gpointer)label); |
1054 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1055 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, |
1056 | + GTK_FILL, GTK_FILL, 5, 5); |
1057 | + |
1058 | + v1_artist_entry = gtk_entry_new_with_max_length(30); |
1059 | + gtk_table_attach(GTK_TABLE(table), v1_artist_entry, 1, 5, 2, 3, |
1060 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1061 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 2); |
1062 | + |
1063 | + label = gtk_label_new("Album:"); |
1064 | + g_ptr_array_add(v1_labels_list, (gpointer)label); |
1065 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1066 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, |
1067 | + GTK_FILL, GTK_FILL, 5, 5); |
1068 | + |
1069 | + v1_album_entry = gtk_entry_new_with_max_length(30); |
1070 | + gtk_table_attach(GTK_TABLE(table), v1_album_entry, 1, 5, 3, 4, |
1071 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1072 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 2); |
1073 | + |
1074 | + label = gtk_label_new("Comment:"); |
1075 | + g_ptr_array_add(v1_labels_list, (gpointer)label); |
1076 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1077 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, |
1078 | + GTK_FILL, GTK_FILL, 5, 5); |
1079 | + |
1080 | + v1_comment_entry = gtk_entry_new_with_max_length(30); |
1081 | + gtk_table_attach(GTK_TABLE(table), v1_comment_entry, 1, 5, 4, 5, |
1082 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1083 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 2); |
1084 | + |
1085 | + label = gtk_label_new("Year:"); |
1086 | + g_ptr_array_add(v1_labels_list, (gpointer)label); |
1087 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1088 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 5, 6, |
1089 | + GTK_FILL, GTK_FILL, 5, 5); |
1090 | + |
1091 | + v1_year_entry = gtk_entry_new_with_max_length(4); |
1092 | + gtk_widget_set_usize(v1_year_entry, 45, -1); |
1093 | + gtk_table_attach(GTK_TABLE(table), v1_year_entry, 1, 2, 5, 6, |
1094 | + GTK_FILL, GTK_FILL, 0, 2); |
1095 | + |
1096 | + label = gtk_label_new("Genre:"); |
1097 | + g_ptr_array_add(v1_labels_list, (gpointer)label); |
1098 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1099 | + gtk_table_attach(GTK_TABLE(table), label, 2, 3, 5, 6, |
1100 | + GTK_FILL, GTK_FILL, 5, 5); |
1101 | + |
1102 | + v1_genre_combo = gtk_combo_new(); |
1103 | + gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(v1_genre_combo)->entry), |
1104 | + FALSE); |
1105 | if (!genre_list) |
1106 | { |
1107 | struct genre_item *item; |
1108 | @@ -408,77 +584,278 @@ |
1109 | genre_list = g_list_prepend(genre_list, item); |
1110 | genre_list = g_list_sort(genre_list, genre_comp_func); |
1111 | } |
1112 | - genre_set_popdown(genre_combo, genre_list); |
1113 | - gtk_signal_connect(GTK_OBJECT(GTK_COMBO(genre_combo)->list), |
1114 | - "select-child", genre_selected, NULL); |
1115 | - |
1116 | - gtk_table_attach(GTK_TABLE(table), genre_combo, 1, 4, 5, 6, |
1117 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1118 | - GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); |
1119 | - |
1120 | - bbox = gtk_hbutton_box_new(); |
1121 | - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), |
1122 | - GTK_BUTTONBOX_END); |
1123 | - gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); |
1124 | - gtk_box_pack_start(GTK_BOX(left_vbox), bbox, FALSE, FALSE, 0); |
1125 | - |
1126 | - save = gtk_button_new_with_label(_("Save")); |
1127 | - gtk_signal_connect(GTK_OBJECT(save), "clicked", save_cb, NULL); |
1128 | - GTK_WIDGET_SET_FLAGS(save, GTK_CAN_DEFAULT); |
1129 | - gtk_box_pack_start(GTK_BOX(bbox), save, TRUE, TRUE, 0); |
1130 | - gtk_widget_grab_default(save); |
1131 | - |
1132 | - remove_id3 = gtk_button_new_with_label(_("Remove ID3")); |
1133 | - gtk_signal_connect(GTK_OBJECT(remove_id3), "clicked", |
1134 | - remove_id3_cb, NULL); |
1135 | - GTK_WIDGET_SET_FLAGS(remove_id3, GTK_CAN_DEFAULT); |
1136 | - gtk_box_pack_start(GTK_BOX(bbox), remove_id3, TRUE, TRUE, 0); |
1137 | - |
1138 | - cancel = gtk_button_new_with_label(_("Cancel")); |
1139 | - gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", |
1140 | - gtk_widget_destroy, GTK_OBJECT(window)); |
1141 | - GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); |
1142 | - gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); |
1143 | - |
1144 | - mpeg_frame = gtk_frame_new(_("MPEG Info:")); |
1145 | - gtk_box_pack_start(GTK_BOX(hbox), mpeg_frame, FALSE, FALSE, 0); |
1146 | - |
1147 | - mpeg_box = gtk_vbox_new(FALSE, 5); |
1148 | - gtk_container_add(GTK_CONTAINER(mpeg_frame), mpeg_box); |
1149 | - gtk_container_set_border_width(GTK_CONTAINER(mpeg_box), 10); |
1150 | - gtk_box_set_spacing(GTK_BOX(mpeg_box), 0); |
1151 | - |
1152 | - mpeg_level = gtk_label_new(""); |
1153 | - gtk_widget_set_usize(mpeg_level, 120, -2); |
1154 | - gtk_misc_set_alignment(GTK_MISC(mpeg_level), 0, 0); |
1155 | - gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_level, FALSE, FALSE, 0); |
1156 | - |
1157 | - mpeg_bitrate = gtk_label_new(""); |
1158 | - gtk_misc_set_alignment(GTK_MISC(mpeg_bitrate), 0, 0); |
1159 | - gtk_label_set_justify(GTK_LABEL(mpeg_bitrate), |
1160 | - GTK_JUSTIFY_LEFT); |
1161 | - gtk_box_pack_start(GTK_BOX(mpeg_box), |
1162 | - mpeg_bitrate, FALSE, FALSE, 0); |
1163 | - |
1164 | - mpeg_samplerate = gtk_label_new(""); |
1165 | - gtk_misc_set_alignment(GTK_MISC(mpeg_samplerate), 0, 0); |
1166 | - gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_samplerate, |
1167 | - FALSE, FALSE, 0); |
1168 | - |
1169 | - mpeg_flags = gtk_label_new(""); |
1170 | - gtk_misc_set_alignment(GTK_MISC(mpeg_flags), 0, 0); |
1171 | - gtk_label_set_justify(GTK_LABEL(mpeg_flags), GTK_JUSTIFY_LEFT); |
1172 | - gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_flags, |
1173 | - FALSE, FALSE, 0); |
1174 | - |
1175 | - mpeg_fileinfo = gtk_label_new(""); |
1176 | - gtk_misc_set_alignment(GTK_MISC(mpeg_fileinfo), 0, 0); |
1177 | - gtk_label_set_justify(GTK_LABEL(mpeg_fileinfo), |
1178 | - GTK_JUSTIFY_LEFT); |
1179 | - gtk_box_pack_start(GTK_BOX(mpeg_box), mpeg_fileinfo, |
1180 | - FALSE, FALSE, 0); |
1181 | + genre_set_popdown(v1_genre_combo, genre_list); |
1182 | + gtk_signal_connect(GTK_OBJECT(GTK_COMBO(v1_genre_combo)->list), |
1183 | + "select-child", v1_genre_selected, NULL); |
1184 | + |
1185 | + gtk_table_attach(GTK_TABLE(table), v1_genre_combo, 3, 5, 5, 6, |
1186 | + GTK_FILL | GTK_SHRINK, GTK_FILL | |
1187 | + GTK_SHRINK, 0, 2); |
1188 | + |
1189 | + bbox = gtk_hbutton_box_new(); |
1190 | + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_START); |
1191 | + gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), 0); |
1192 | + gtk_container_set_border_width(GTK_CONTAINER(bbox), 5); |
1193 | + gtk_box_pack_start(GTK_BOX(id3v1_frame_vbox), bbox, FALSE, FALSE, 0); |
1194 | + |
1195 | + copy_from = gtk_button_new_with_label("ID3v1 to ID3v2"); |
1196 | + gtk_signal_connect(GTK_OBJECT(copy_from), "clicked", GTK_SIGNAL_FUNC(copy_v1_to_v2_cb), NULL); |
1197 | + // remove the next line to thicken the button width |
1198 | + GTK_WIDGET_SET_FLAGS(copy_from, GTK_CAN_DEFAULT); |
1199 | + gtk_box_pack_start(GTK_BOX(bbox), copy_from, FALSE, TRUE, 0); |
1200 | + |
1201 | + |
1202 | + notebook = gtk_notebook_new (); |
1203 | + gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP); |
1204 | + |
1205 | + label = gtk_label_new ("ID3v1"); |
1206 | + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), id3v1_vbox, label); |
1207 | + |
1208 | + |
1209 | + //////////////////////////////////////////////////////////////////////////////////////////////////// |
1210 | + //////////////////////////////////////////////////////////////////////////////////////////////////// |
1211 | + |
1212 | + id3v2_vbox = gtk_vbox_new(FALSE, 0); |
1213 | + |
1214 | + id3v2_frame = gtk_frame_new("ID3v2 Information"); |
1215 | + gtk_box_pack_start(GTK_BOX(id3v2_vbox), id3v2_frame, FALSE, FALSE, 0); |
1216 | + |
1217 | + id3v2_frame_vbox = gtk_vbox_new(FALSE, 0); |
1218 | + gtk_container_add(GTK_CONTAINER(id3v2_frame), id3v2_frame_vbox); |
1219 | + |
1220 | + table = gtk_table_new(6, 6, FALSE); |
1221 | + gtk_container_set_border_width(GTK_CONTAINER(table), 5); |
1222 | + gtk_widget_set_usize(GTK_WIDGET(table), 400, -1); |
1223 | + //gtk_container_add(GTK_CONTAINER(id3v2_frame), table); |
1224 | + gtk_box_pack_start(GTK_BOX(id3v2_frame_vbox), table, FALSE, FALSE, 0); |
1225 | + |
1226 | + v2_checkbox = gtk_check_button_new_with_label ("Disable ID3v2 Tag"); |
1227 | + gtk_signal_connect(GTK_OBJECT(v2_checkbox), "toggled", GTK_SIGNAL_FUNC(v2_toggle_cb), NULL); |
1228 | + gtk_table_attach(GTK_TABLE(table), v2_checkbox, 1, 3, 0, 1, |
1229 | + GTK_FILL, GTK_FILL, 0, 2); |
1230 | + |
1231 | + label = gtk_label_new("Track number:"); |
1232 | + g_ptr_array_add(v2_labels_list, (gpointer)label); |
1233 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1234 | + gtk_table_attach(GTK_TABLE(table), label, 3, 4, 0, 1, |
1235 | + GTK_FILL, GTK_FILL, 5,5); |
1236 | + |
1237 | + v2_tracknum_entry = gtk_entry_new_with_max_length(3); |
1238 | + gtk_widget_set_usize(v2_tracknum_entry, 20, -1); |
1239 | + gtk_table_attach(GTK_TABLE(table), v2_tracknum_entry, 4, 5, 0, 1, |
1240 | + GTK_FILL, GTK_FILL, 0, 2); |
1241 | + |
1242 | + label = gtk_label_new("Title:"); |
1243 | + g_ptr_array_add(v2_labels_list, (gpointer)label); |
1244 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1245 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, |
1246 | + GTK_FILL, GTK_FILL, 5, 5); |
1247 | + |
1248 | + v2_title_entry = gtk_entry_new_with_max_length(MAX_ENTRY_LEN2); |
1249 | + gtk_table_attach(GTK_TABLE(table), v2_title_entry, 1, 5, 1, 2, |
1250 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1251 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 2); |
1252 | + |
1253 | + label = gtk_label_new("Artist:"); |
1254 | + g_ptr_array_add(v2_labels_list, (gpointer)label); |
1255 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1256 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, |
1257 | + GTK_FILL, GTK_FILL, 5, 5); |
1258 | + |
1259 | + v2_artist_entry = gtk_entry_new_with_max_length(MAX_ENTRY_LEN2); |
1260 | + gtk_table_attach(GTK_TABLE(table), v2_artist_entry, 1, 5, 2, 3, |
1261 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1262 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 2); |
1263 | + |
1264 | + label = gtk_label_new("Album:"); |
1265 | + g_ptr_array_add(v2_labels_list, (gpointer)label); |
1266 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1267 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, |
1268 | + GTK_FILL, GTK_FILL, 5, 5); |
1269 | + |
1270 | + v2_album_entry = gtk_entry_new_with_max_length(MAX_ENTRY_LEN2); |
1271 | + gtk_table_attach(GTK_TABLE(table), v2_album_entry, 1, 5, 3, 4, |
1272 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1273 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 2); |
1274 | + |
1275 | + label = gtk_label_new("Comment:"); |
1276 | + g_ptr_array_add(v2_labels_list, (gpointer)label); |
1277 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1278 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, |
1279 | + GTK_FILL, GTK_FILL, 5, 5); |
1280 | + |
1281 | + v2_comment_entry = gtk_entry_new_with_max_length(MAX_ENTRY_LEN2); |
1282 | + gtk_table_attach(GTK_TABLE(table), v2_comment_entry, 1, 5, 4, 5, |
1283 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1284 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 2); |
1285 | + |
1286 | + label = gtk_label_new("Year:"); |
1287 | + g_ptr_array_add(v2_labels_list, (gpointer)label); |
1288 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1289 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 5, 6, |
1290 | + GTK_FILL, GTK_FILL, 5, 5); |
1291 | + |
1292 | + v2_year_entry = gtk_entry_new_with_max_length(4); |
1293 | + gtk_widget_set_usize(v2_year_entry, 45, -1); |
1294 | + gtk_table_attach(GTK_TABLE(table), v2_year_entry, 1, 2, 5, 6, |
1295 | + GTK_FILL, GTK_FILL, 0, 2); |
1296 | + |
1297 | + label = gtk_label_new("Genre:"); |
1298 | + g_ptr_array_add(v2_labels_list, (gpointer)label); |
1299 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1300 | + gtk_table_attach(GTK_TABLE(table), label, 2, 3, 5, 6, |
1301 | + GTK_FILL, GTK_FILL, 5, 5); |
1302 | + |
1303 | + v2_genre_combo = gtk_combo_new(); |
1304 | + gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(v2_genre_combo)->entry), FALSE); |
1305 | + genre_set_popdown(v2_genre_combo, genre_list); |
1306 | + gtk_signal_connect(GTK_OBJECT(GTK_COMBO(v2_genre_combo)->list), |
1307 | + "select-child", v2_genre_selected, NULL); |
1308 | + |
1309 | + gtk_table_attach(GTK_TABLE(table), v2_genre_combo, 3, 5, 5, 6, |
1310 | + GTK_FILL | GTK_SHRINK, GTK_FILL | |
1311 | + GTK_SHRINK, 0, 2); |
1312 | + |
1313 | + label = gtk_label_new("Composer:"); |
1314 | + g_ptr_array_add(v2_labels_list, (gpointer)label); |
1315 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1316 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 6, 7, |
1317 | + GTK_FILL, GTK_FILL, 5, 5); |
1318 | + |
1319 | + v2_composer_entry = gtk_entry_new_with_max_length(MAX_ENTRY_LEN2); |
1320 | + gtk_table_attach(GTK_TABLE(table), v2_composer_entry, 1, 5, 6, 7, |
1321 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1322 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 2); |
1323 | + |
1324 | + label = gtk_label_new("Orig. Artist:"); |
1325 | + g_ptr_array_add(v2_labels_list, (gpointer)label); |
1326 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1327 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 7, 8, |
1328 | + GTK_FILL, GTK_FILL, 5, 5); |
1329 | + |
1330 | + v2_orig_artist_entry = gtk_entry_new_with_max_length(MAX_ENTRY_LEN2); |
1331 | + gtk_table_attach(GTK_TABLE(table), v2_orig_artist_entry, 1, 5, 7, 8, |
1332 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1333 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 2); |
1334 | + |
1335 | + label = gtk_label_new("URL:"); |
1336 | + g_ptr_array_add(v2_labels_list, (gpointer)label); |
1337 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1338 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 8, 9, |
1339 | + GTK_FILL, GTK_FILL, 5, 5); |
1340 | + |
1341 | + v2_url_entry = gtk_entry_new_with_max_length(MAX_ENTRY_LEN2); |
1342 | + gtk_table_attach(GTK_TABLE(table), v2_url_entry, 1, 5, 8, 9, |
1343 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1344 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 2); |
1345 | + label = gtk_label_new("Encoded By:"); |
1346 | + g_ptr_array_add(v2_labels_list, (gpointer)label); |
1347 | + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); |
1348 | + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 9, 10, |
1349 | + GTK_FILL, GTK_FILL, 5, 5); |
1350 | + |
1351 | + v2_encoded_by_entry = gtk_entry_new_with_max_length(MAX_ENTRY_LEN2); |
1352 | + gtk_table_attach(GTK_TABLE(table), v2_encoded_by_entry, 1, 5, 9, 10, |
1353 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, |
1354 | + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 2); |
1355 | + |
1356 | + bbox = gtk_hbutton_box_new(); |
1357 | + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_START); |
1358 | + gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), 0); |
1359 | + gtk_container_set_border_width(GTK_CONTAINER(bbox), 5); |
1360 | + gtk_box_pack_start(GTK_BOX(id3v2_frame_vbox), bbox, FALSE, FALSE, 0); |
1361 | + |
1362 | + copy_to = gtk_button_new_with_label("ID3v2 to ID3v1"); |
1363 | + gtk_signal_connect(GTK_OBJECT(copy_to), "clicked", GTK_SIGNAL_FUNC(copy_v2_to_v1_cb), NULL); |
1364 | + // remove the next line to thicken the button width |
1365 | + GTK_WIDGET_SET_FLAGS(copy_to, GTK_CAN_DEFAULT); |
1366 | + gtk_box_pack_start(GTK_BOX(bbox), copy_to, FALSE, TRUE, 0); |
1367 | + |
1368 | + label = gtk_label_new ("ID3v2"); |
1369 | + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), id3v2_vbox, label); |
1370 | + |
1371 | + |
1372 | + //////////////////////////////////////////////////////////////////////////////////////////////////// |
1373 | + //////////////////////////////////////////////////////////////////////////////////////////////////// |
1374 | + |
1375 | + mpeg_frame = gtk_frame_new("MPEG Information"); |
1376 | + mpeg_hbox = gtk_hbox_new(FALSE,50); |
1377 | + gtk_container_add(GTK_CONTAINER(mpeg_frame), mpeg_hbox); |
1378 | + |
1379 | + mpeg_lvbox = gtk_vbox_new(FALSE, 5); |
1380 | + gtk_container_set_border_width(GTK_CONTAINER(mpeg_lvbox), 10); |
1381 | + gtk_box_pack_start(GTK_BOX(mpeg_hbox), mpeg_lvbox, FALSE, FALSE, 0); |
1382 | + |
1383 | + //gtk_container_set_border_width(GTK_CONTAINER(table), 5); |
1384 | + //gtk_widget_set_usize(GTK_WIDGET(table), 325, -1); |
1385 | + //gtk_container_add(GTK_CONTAINER(mpeg_frame), table); |
1386 | + |
1387 | + mpeg_box = gtk_vbox_new(FALSE, 5); |
1388 | + gtk_box_pack_start(GTK_BOX(mpeg_hbox), mpeg_box, FALSE, FALSE, 0); |
1389 | + gtk_container_set_border_width(GTK_CONTAINER(mpeg_box), 10); |
1390 | + gtk_box_set_spacing(GTK_BOX(mpeg_box), 0); |
1391 | + |
1392 | + mpeg_level = gtk_label_new(""); |
1393 | + //gtk_widget_set_usize(mpeg_level, 120, -2); |
1394 | + gtk_label_set_justify (GTK_LABEL(mpeg_level), GTK_JUSTIFY_LEFT); |
1395 | + gtk_misc_set_alignment(GTK_MISC(mpeg_level), 0, 0.5); |
1396 | + gtk_box_pack_start(GTK_BOX(mpeg_lvbox), mpeg_level, FALSE, FALSE, 0); |
1397 | + |
1398 | + mpeg_samplerate = gtk_label_new(""); |
1399 | + gtk_label_set_justify (GTK_LABEL(mpeg_samplerate), GTK_JUSTIFY_LEFT); |
1400 | + gtk_misc_set_alignment(GTK_MISC(mpeg_samplerate), 0, 0.5); |
1401 | + gtk_box_pack_start(GTK_BOX(mpeg_lvbox), mpeg_samplerate, FALSE, FALSE, 0); |
1402 | + |
1403 | + mpeg_fileinfo = gtk_label_new(""); |
1404 | + gtk_label_set_justify (GTK_LABEL(mpeg_fileinfo), GTK_JUSTIFY_LEFT); |
1405 | + gtk_misc_set_alignment(GTK_MISC(mpeg_fileinfo), 0, 0.5); |
1406 | + gtk_box_pack_start(GTK_BOX(mpeg_lvbox), mpeg_fileinfo, FALSE, FALSE, 0); |
1407 | + |
1408 | + mpeg_rvbox = gtk_vbox_new(FALSE, 5); |
1409 | + gtk_box_pack_start(GTK_BOX(mpeg_hbox), mpeg_rvbox, FALSE, FALSE, 0); |
1410 | + gtk_container_set_border_width(GTK_CONTAINER(mpeg_rvbox), 10); |
1411 | + |
1412 | + mpeg_bitrate = gtk_label_new(""); |
1413 | + gtk_label_set_justify (GTK_LABEL(mpeg_bitrate), GTK_JUSTIFY_LEFT); |
1414 | + gtk_misc_set_alignment(GTK_MISC(mpeg_bitrate), 0, 0.5); |
1415 | + gtk_box_pack_start(GTK_BOX(mpeg_rvbox), mpeg_bitrate, FALSE, FALSE, 0); |
1416 | + |
1417 | + mpeg_flags = gtk_label_new(""); |
1418 | + gtk_label_set_justify (GTK_LABEL(mpeg_flags), GTK_JUSTIFY_LEFT); |
1419 | + gtk_misc_set_alignment(GTK_MISC(mpeg_flags), 0, 0.5); |
1420 | + gtk_box_pack_start(GTK_BOX(mpeg_rvbox), mpeg_flags, FALSE, FALSE, 0); |
1421 | + |
1422 | + label = gtk_label_new ("MPEG"); |
1423 | + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), mpeg_frame, label); |
1424 | + |
1425 | + ////////////////////////////////////////////////////////////////// |
1426 | + ////////////////////////////////////////////////////////////////// |
1427 | + |
1428 | + // add notebook to window vbox |
1429 | + gtk_box_pack_start(GTK_BOX(window_vbox), notebook, FALSE, FALSE, 0); |
1430 | + |
1431 | + // add button box to window vbox |
1432 | + bbox = gtk_hbutton_box_new(); |
1433 | + gtk_box_pack_start(GTK_BOX(window_vbox), bbox, FALSE, FALSE, 0); |
1434 | + |
1435 | + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); |
1436 | + gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), 5); |
1437 | + //gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h); |
1438 | + |
1439 | + save = gtk_button_new_with_label("Save"); |
1440 | + gtk_signal_connect(GTK_OBJECT(save), "clicked", GTK_SIGNAL_FUNC(save_cb), NULL); |
1441 | + //GTK_WIDGET_SET_FLAGS(save, GTK_CAN_DEFAULT); |
1442 | + gtk_box_pack_start(GTK_BOX(bbox), save, TRUE, TRUE, 5); |
1443 | + //gtk_widget_grab_default(save); |
1444 | + |
1445 | + close = gtk_button_new_with_label("Close"); |
1446 | + gtk_signal_connect_object(GTK_OBJECT(close), "clicked", |
1447 | + GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window)); |
1448 | + //GTK_WIDGET_SET_FLAGS(close, GTK_CAN_DEFAULT); |
1449 | + gtk_box_pack_start(GTK_BOX(bbox), close, TRUE, TRUE, 5); |
1450 | |
1451 | - gtk_widget_show_all(window); |
1452 | + gtk_container_add(GTK_CONTAINER(window), window_vbox); |
1453 | + gtk_widget_show_all(window); |
1454 | } |
1455 | |
1456 | if (current_filename) |
1457 | @@ -495,29 +872,43 @@ |
1458 | title = g_strdup(g_basename(filename)); |
1459 | if ((tmp = strrchr(title, '.')) != NULL) |
1460 | *tmp = '\0'; |
1461 | - gtk_entry_set_text(GTK_ENTRY(title_entry), title); |
1462 | + gtk_entry_set_text(GTK_ENTRY(v1_title_entry), title); |
1463 | + gtk_entry_set_text(GTK_ENTRY(v2_title_entry), title); |
1464 | g_free(title); |
1465 | |
1466 | - gtk_entry_set_text(GTK_ENTRY(artist_entry), ""); |
1467 | - gtk_entry_set_text(GTK_ENTRY(album_entry), ""); |
1468 | - gtk_entry_set_text(GTK_ENTRY(year_entry), ""); |
1469 | - gtk_entry_set_text(GTK_ENTRY(tracknum_entry), ""); |
1470 | - gtk_entry_set_text(GTK_ENTRY(comment_entry), ""); |
1471 | - gtk_list_select_item(GTK_LIST(GTK_COMBO(genre_combo)->list), |
1472 | + gtk_entry_set_text(GTK_ENTRY(v1_artist_entry), ""); |
1473 | + gtk_entry_set_text(GTK_ENTRY(v1_album_entry), ""); |
1474 | + gtk_entry_set_text(GTK_ENTRY(v1_year_entry), ""); |
1475 | + gtk_entry_set_text(GTK_ENTRY(v1_tracknum_entry), ""); |
1476 | + gtk_entry_set_text(GTK_ENTRY(v1_comment_entry), ""); |
1477 | + gtk_list_select_item(GTK_LIST(GTK_COMBO(v1_genre_combo)->list), |
1478 | + genre_find_index(genre_list, 0xff)); |
1479 | + |
1480 | + gtk_entry_set_text(GTK_ENTRY(v2_artist_entry), ""); |
1481 | + gtk_entry_set_text(GTK_ENTRY(v2_album_entry), ""); |
1482 | + gtk_entry_set_text(GTK_ENTRY(v2_year_entry), ""); |
1483 | + gtk_entry_set_text(GTK_ENTRY(v2_tracknum_entry), ""); |
1484 | + gtk_entry_set_text(GTK_ENTRY(v2_comment_entry), ""); |
1485 | + gtk_entry_set_text(GTK_ENTRY(v2_composer_entry), ""); |
1486 | + gtk_entry_set_text(GTK_ENTRY(v2_orig_artist_entry), ""); |
1487 | + gtk_entry_set_text(GTK_ENTRY(v2_url_entry), ""); |
1488 | + gtk_entry_set_text(GTK_ENTRY(v2_encoded_by_entry), ""); |
1489 | + gtk_list_select_item(GTK_LIST(GTK_COMBO(v2_genre_combo)->list), |
1490 | genre_find_index(genre_list, 0xff)); |
1491 | + |
1492 | gtk_label_set_text(GTK_LABEL(mpeg_level), "MPEG ?, layer ?"); |
1493 | gtk_label_set_text(GTK_LABEL(mpeg_bitrate), ""); |
1494 | gtk_label_set_text(GTK_LABEL(mpeg_samplerate), ""); |
1495 | gtk_label_set_text(GTK_LABEL(mpeg_flags), ""); |
1496 | gtk_label_set_text(GTK_LABEL(mpeg_fileinfo), ""); |
1497 | - |
1498 | if (!strncasecmp(filename, "http://", 7)) |
1499 | { |
1500 | file_info_http(filename); |
1501 | return; |
1502 | } |
1503 | |
1504 | - gtk_widget_set_sensitive(id3_frame, TRUE); |
1505 | + gtk_widget_set_sensitive(id3v1_frame, TRUE); |
1506 | + gtk_widget_set_sensitive(id3v2_frame, TRUE); |
1507 | |
1508 | if ((fh = fopen(current_filename, "rb")) != NULL) |
1509 | { |
1510 | @@ -525,40 +916,95 @@ |
1511 | unsigned char tmp[4]; |
1512 | struct frame frm; |
1513 | gboolean id3_found = FALSE; |
1514 | + char *temp = NULL; |
1515 | + struct id3_tag *id3 = NULL; |
1516 | |
1517 | - fseek(fh, -sizeof (tag), SEEK_END); |
1518 | - if (fread(&tag, 1, sizeof (tag), fh) == sizeof (tag)) |
1519 | + /* |
1520 | + * Try reading ID3v2 tag. |
1521 | + */ |
1522 | + if (!mpg123_cfg.disable_id3v2) |
1523 | { |
1524 | - if (!strncmp(tag.tag, "TAG", 3)) |
1525 | + fseek(fh, 0, SEEK_SET); |
1526 | + id3 = id3_open_fp(fh, 0); |
1527 | + if (id3) |
1528 | { |
1529 | - id3_found = TRUE; |
1530 | - set_entry_tag(GTK_ENTRY(title_entry), |
1531 | - tag.title, 30); |
1532 | - set_entry_tag(GTK_ENTRY(artist_entry), |
1533 | - tag.artist, 30); |
1534 | - set_entry_tag(GTK_ENTRY(album_entry), |
1535 | - tag.album, 30); |
1536 | - set_entry_tag(GTK_ENTRY(year_entry), |
1537 | - tag.year, 4); |
1538 | - /* Check for v1.1 tags */ |
1539 | - if (tag.u.v1_1.__zero == 0) |
1540 | - { |
1541 | - char *temp = g_strdup_printf("%d", tag.u.v1_1.track_number); |
1542 | - set_entry_tag(GTK_ENTRY(comment_entry), |
1543 | - tag.u.v1_1.comment, 28); |
1544 | - gtk_entry_set_text(GTK_ENTRY(tracknum_entry), temp); |
1545 | - g_free(temp); |
1546 | - } |
1547 | - else |
1548 | - { |
1549 | - set_entry_tag(GTK_ENTRY(comment_entry), |
1550 | - tag.u.v1_0.comment, 30); |
1551 | - gtk_entry_set_text(GTK_ENTRY(tracknum_entry), ""); |
1552 | - } |
1553 | + mpg123_get_id3v2(id3, &id3v2tag); |
1554 | + set_entry_tag(GTK_ENTRY(v2_title_entry), |
1555 | + id3v2tag.title, 128); |
1556 | + set_entry_tag(GTK_ENTRY(v2_artist_entry), |
1557 | + id3v2tag.artist, 128); |
1558 | + set_entry_tag(GTK_ENTRY(v2_album_entry), |
1559 | + id3v2tag.album, 128); |
1560 | + set_entry_tag(GTK_ENTRY(v2_comment_entry), |
1561 | + id3v2tag.comment, 256); |
1562 | + set_entry_tag(GTK_ENTRY(v2_composer_entry), |
1563 | + id3v2tag.composer, MAX_ENTRY_LEN2); |
1564 | + set_entry_tag(GTK_ENTRY(v2_orig_artist_entry), |
1565 | + id3v2tag.orig_artist, MAX_ENTRY_LEN2); |
1566 | + set_entry_tag(GTK_ENTRY(v2_url_entry), |
1567 | + id3v2tag.url, MAX_ENTRY_LEN2); |
1568 | + set_entry_tag(GTK_ENTRY(v2_encoded_by_entry), |
1569 | + id3v2tag.encoded_by, MAX_ENTRY_LEN2); |
1570 | |
1571 | - gtk_list_select_item(GTK_LIST(GTK_COMBO(genre_combo)->list), genre_find_index(genre_list, tag.genre)); |
1572 | + temp = g_strdup_printf("%d", id3v2tag.track_number); |
1573 | + gtk_entry_set_text(GTK_ENTRY(v2_tracknum_entry), temp); |
1574 | + g_free(temp); |
1575 | + |
1576 | + temp = g_strdup_printf("%d", id3v2tag.year); |
1577 | + gtk_entry_set_text(GTK_ENTRY(v2_year_entry), temp); |
1578 | + g_free(temp); |
1579 | + |
1580 | + printf("Loading genre: %s", id3v2tag.genre); |
1581 | + gtk_list_select_item(GTK_LIST(GTK_COMBO(v2_genre_combo)->list), genre_find_index_str(genre_list, id3v2tag.genre)); |
1582 | + id3_close(id3); |
1583 | } |
1584 | + else |
1585 | + { |
1586 | + // Grey out the id3v2 tab |
1587 | + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(v2_checkbox), TRUE); |
1588 | + } |
1589 | + } |
1590 | + |
1591 | + /* |
1592 | + * Try reading ID3v1 tag. |
1593 | + */ |
1594 | + fseek(fh, -sizeof (id3v1tag), SEEK_END); |
1595 | + if ( (fread(&id3v1tag, 1, sizeof (id3v1tag), fh) == sizeof (id3v1tag)) && |
1596 | + !strncmp(id3v1tag.tag, "TAG", 3)) |
1597 | + { |
1598 | + id3_found = TRUE; |
1599 | + set_entry_tag(GTK_ENTRY(v1_title_entry), |
1600 | + id3v1tag.title, 30); |
1601 | + set_entry_tag(GTK_ENTRY(v1_artist_entry), |
1602 | + id3v1tag.artist, 30); |
1603 | + set_entry_tag(GTK_ENTRY(v1_album_entry), |
1604 | + id3v1tag.album, 30); |
1605 | + set_entry_tag(GTK_ENTRY(v1_year_entry), |
1606 | + id3v1tag.year, 4); |
1607 | + /* Check for v1.1 tags */ |
1608 | + if (id3v1tag.u.v1_1.__zero == 0) |
1609 | + { |
1610 | + char *temp = g_strdup_printf("%d", id3v1tag.u.v1_1.track_number); |
1611 | + set_entry_tag(GTK_ENTRY(v1_comment_entry), |
1612 | + id3v1tag.u.v1_1.comment, 28); |
1613 | + gtk_entry_set_text(GTK_ENTRY(v1_tracknum_entry), temp); |
1614 | + g_free(temp); |
1615 | + } |
1616 | + else |
1617 | + { |
1618 | + set_entry_tag(GTK_ENTRY(v1_comment_entry), |
1619 | + id3v1tag.u.v1_0.comment, 30); |
1620 | + gtk_entry_set_text(GTK_ENTRY(v1_tracknum_entry), ""); |
1621 | + } |
1622 | + |
1623 | + gtk_list_select_item(GTK_LIST(GTK_COMBO(v1_genre_combo)->list), genre_find_index(genre_list, id3v1tag.genre)); |
1624 | } |
1625 | + else |
1626 | + { |
1627 | + // Grey out id3v1 tab |
1628 | + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(v1_checkbox), TRUE); |
1629 | + } |
1630 | + |
1631 | rewind(fh); |
1632 | if (fread(tmp, 1, 4, fh) != 4) |
1633 | { |
1634 | diff -Naur xmms-1.2.9-orig/Input/mpg123/id3.h xmms-1.2.9/Input/mpg123/id3.h |
1635 | --- xmms-1.2.9-orig/Input/mpg123/id3.h Thu Jan 29 06:43:24 2004 |
1636 | +++ xmms-1.2.9/Input/mpg123/id3.h Thu Jan 29 05:20:31 2004 |
1637 | @@ -351,6 +351,7 @@ |
1638 | int id3_set_text(struct id3_frame *, char *); |
1639 | int id3_set_text_number(struct id3_frame *, int); |
1640 | gboolean id3_frame_is_text(struct id3_frame *frame); |
1641 | +char* id3_get_comm(struct id3_frame *frame); |
1642 | |
1643 | /* From id3_frame_content.c */ |
1644 | char *id3_get_content(struct id3_frame *); |
1645 | diff -Naur xmms-1.2.9-orig/Input/mpg123/id3_frame_text.c xmms-1.2.9/Input/mpg123/id3_frame_text.c |
1646 | --- xmms-1.2.9-orig/Input/mpg123/id3_frame_text.c Thu Jan 29 06:43:24 2004 |
1647 | +++ xmms-1.2.9/Input/mpg123/id3_frame_text.c Thu Jan 29 05:18:54 2004 |
1648 | @@ -38,15 +38,15 @@ |
1649 | |
1650 | char *id3_utf16_to_ascii(void *utf16) |
1651 | { |
1652 | - char ascii[256]; |
1653 | - char *uc = (char *) utf16 + 2; |
1654 | - int i; |
1655 | - |
1656 | - for (i = 0; *uc != 0 && i < sizeof(ascii); i++, uc += 2) |
1657 | - ascii[i] = *uc; |
1658 | - |
1659 | - ascii[i] = 0; |
1660 | - return g_strdup(ascii); |
1661 | + char ascii[256]; |
1662 | + char *uc = (char *) utf16 + 2; |
1663 | + int i; |
1664 | + |
1665 | + for (i = 0; *uc != 0 && i < sizeof(ascii); i++, uc += 2) |
1666 | + ascii[i] = *uc; |
1667 | + |
1668 | + ascii[i] = 0; |
1669 | + return g_strdup(ascii); |
1670 | } |
1671 | |
1672 | |
1673 | @@ -59,25 +59,25 @@ |
1674 | */ |
1675 | gint8 id3_get_encoding(struct id3_frame *frame) |
1676 | { |
1677 | - /* Type check */ |
1678 | - if (!id3_frame_is_text(frame) && |
1679 | - frame->fr_desc->fd_id != ID3_WXXX && |
1680 | - frame->fr_desc->fd_id != ID3_IPLS && |
1681 | - frame->fr_desc->fd_id != ID3_USLT && |
1682 | - frame->fr_desc->fd_id != ID3_SYLT && |
1683 | - frame->fr_desc->fd_id != ID3_COMM && |
1684 | - frame->fr_desc->fd_id != ID3_APIC && |
1685 | - frame->fr_desc->fd_id != ID3_GEOB && |
1686 | - frame->fr_desc->fd_id != ID3_USER && |
1687 | - frame->fr_desc->fd_id != ID3_OWNE && |
1688 | - frame->fr_desc->fd_id != ID3_COMR) |
1689 | - return -1; |
1690 | - |
1691 | - /* Check if frame is compressed */ |
1692 | - if (id3_decompress_frame(frame) == -1) |
1693 | - return -1; |
1694 | + /* Type check */ |
1695 | + if (!id3_frame_is_text(frame) && |
1696 | + frame->fr_desc->fd_id != ID3_WXXX && |
1697 | + frame->fr_desc->fd_id != ID3_IPLS && |
1698 | + frame->fr_desc->fd_id != ID3_USLT && |
1699 | + frame->fr_desc->fd_id != ID3_SYLT && |
1700 | + frame->fr_desc->fd_id != ID3_COMM && |
1701 | + frame->fr_desc->fd_id != ID3_APIC && |
1702 | + frame->fr_desc->fd_id != ID3_GEOB && |
1703 | + frame->fr_desc->fd_id != ID3_USER && |
1704 | + frame->fr_desc->fd_id != ID3_OWNE && |
1705 | + frame->fr_desc->fd_id != ID3_COMR) |
1706 | + return -1; |
1707 | + |
1708 | + /* Check if frame is compressed */ |
1709 | + if (id3_decompress_frame(frame) == -1) |
1710 | + return -1; |
1711 | |
1712 | - return *(gint8 *) frame->fr_data; |
1713 | + return *(gint8 *) frame->fr_data; |
1714 | } |
1715 | |
1716 | |
1717 | @@ -92,25 +92,25 @@ |
1718 | { |
1719 | /* Type check */ |
1720 | if ( frame->fr_desc->fd_idstr[0] != 'T' && |
1721 | - frame->fr_desc->fd_id != ID3_WXXX && |
1722 | - frame->fr_desc->fd_id != ID3_IPLS && |
1723 | - frame->fr_desc->fd_id != ID3_USLT && |
1724 | - frame->fr_desc->fd_id != ID3_SYLT && |
1725 | - frame->fr_desc->fd_id != ID3_COMM && |
1726 | - frame->fr_desc->fd_id != ID3_APIC && |
1727 | - frame->fr_desc->fd_id != ID3_GEOB && |
1728 | - frame->fr_desc->fd_id != ID3_USER && |
1729 | - frame->fr_desc->fd_id != ID3_OWNE && |
1730 | - frame->fr_desc->fd_id != ID3_COMR ) |
1731 | - return -1; |
1732 | + frame->fr_desc->fd_id != ID3_WXXX && |
1733 | + frame->fr_desc->fd_id != ID3_IPLS && |
1734 | + frame->fr_desc->fd_id != ID3_USLT && |
1735 | + frame->fr_desc->fd_id != ID3_SYLT && |
1736 | + frame->fr_desc->fd_id != ID3_COMM && |
1737 | + frame->fr_desc->fd_id != ID3_APIC && |
1738 | + frame->fr_desc->fd_id != ID3_GEOB && |
1739 | + frame->fr_desc->fd_id != ID3_USER && |
1740 | + frame->fr_desc->fd_id != ID3_OWNE && |
1741 | + frame->fr_desc->fd_id != ID3_COMR ) |
1742 | + return -1; |
1743 | |
1744 | /* Check if frame is compressed */ |
1745 | if (id3_decompress_frame(frame) == -1) |
1746 | - return -1; |
1747 | + return -1; |
1748 | |
1749 | /* Changing the encoding of frames is not supported yet */ |
1750 | if ( *(gint8 *) frame->fr_data != encoding ) |
1751 | - return -1; |
1752 | + return -1; |
1753 | |
1754 | /* Set encoding */ |
1755 | *(gint8 *) frame->fr_data = encoding; |
1756 | @@ -128,44 +128,44 @@ |
1757 | { |
1758 | /* Type check */ |
1759 | if ( frame->fr_desc->fd_idstr[0] != 'T' ) |
1760 | - return NULL; |
1761 | + return NULL; |
1762 | |
1763 | /* Check if frame is compressed */ |
1764 | if (id3_decompress_frame(frame) == -1) |
1765 | - return NULL; |
1766 | + return NULL; |
1767 | |
1768 | if ( frame->fr_desc->fd_id == ID3_TXXX ) { |
1769 | - /* |
1770 | - * This is a user defined text frame. Skip the description. |
1771 | - */ |
1772 | - switch ( *(guint8 *) frame->fr_data ) { |
1773 | - case ID3_ENCODING_ISO_8859_1: |
1774 | - { |
1775 | - char *text = (char *) frame->fr_data + 1; |
1776 | - |
1777 | - while ( *text != 0 ) |
1778 | - text++; |
1779 | - |
1780 | - return g_strdup(++text); |
1781 | - } |
1782 | - case ID3_ENCODING_UTF16: |
1783 | - { |
1784 | - char *text16 = (char *) frame->fr_data + 1; |
1785 | - |
1786 | - while (*text16 != 0 || *(text16 + 1) != 0) |
1787 | - text16 += 2; |
1788 | - |
1789 | - return id3_utf16_to_ascii(text16 + 2); |
1790 | - } |
1791 | - default: |
1792 | - return NULL; |
1793 | - } |
1794 | + /* |
1795 | + * This is a user defined text frame. Skip the description. |
1796 | + */ |
1797 | + switch ( *(guint8 *) frame->fr_data ) { |
1798 | + case ID3_ENCODING_ISO_8859_1: |
1799 | + { |
1800 | + char *text = (char *) frame->fr_data + 1; |
1801 | + |
1802 | + while ( *text != 0 ) |
1803 | + text++; |
1804 | + |
1805 | + return g_strdup(++text); |
1806 | + } |
1807 | + case ID3_ENCODING_UTF16: |
1808 | + { |
1809 | + char *text16 = (char *) frame->fr_data + 1; |
1810 | + |
1811 | + while (*text16 != 0 || *(text16 + 1) != 0) |
1812 | + text16 += 2; |
1813 | + |
1814 | + return id3_utf16_to_ascii(text16 + 2); |
1815 | + } |
1816 | + default: |
1817 | + return NULL; |
1818 | + } |
1819 | } |
1820 | |
1821 | if (*(guint8 *) frame->fr_data == ID3_ENCODING_ISO_8859_1) |
1822 | - return g_strdup((char *) frame->fr_data + 1); |
1823 | + return g_strdup((char *) frame->fr_data + 1); |
1824 | else |
1825 | - return id3_utf16_to_ascii(((char *) frame->fr_data + 1)); |
1826 | + return id3_utf16_to_ascii(((char *) frame->fr_data + 1)); |
1827 | } |
1828 | |
1829 | |
1830 | @@ -179,20 +179,20 @@ |
1831 | { |
1832 | /* Type check */ |
1833 | if ( frame->fr_desc->fd_idstr[0] != 'T' ) |
1834 | - return NULL; |
1835 | + return NULL; |
1836 | |
1837 | /* If predefined text frame, return description. */ |
1838 | if ( frame->fr_desc->fd_id != ID3_TXXX ) |
1839 | - return frame->fr_desc->fd_description; |
1840 | + return frame->fr_desc->fd_description; |
1841 | |
1842 | /* Check if frame is compressed */ |
1843 | if (id3_decompress_frame(frame) == -1) |
1844 | - return NULL; |
1845 | + return NULL; |
1846 | |
1847 | if (*(guint8 *) frame->fr_data == ID3_ENCODING_ISO_8859_1) |
1848 | - return g_strdup((char *) frame->fr_data + 1); |
1849 | + return g_strdup((char *) frame->fr_data + 1); |
1850 | else |
1851 | - return id3_utf16_to_ascii((char *) frame->fr_data + 1); |
1852 | + return id3_utf16_to_ascii((char *) frame->fr_data + 1); |
1853 | } |
1854 | |
1855 | |
1856 | @@ -209,42 +209,42 @@ |
1857 | |
1858 | /* Check if frame is compressed */ |
1859 | if (id3_decompress_frame(frame) == -1) |
1860 | - return -1; |
1861 | + return -1; |
1862 | |
1863 | /* |
1864 | * Generate integer according to encoding. |
1865 | */ |
1866 | switch ( *(guint8 *) frame->fr_data ) { |
1867 | - case ID3_ENCODING_ISO_8859_1: |
1868 | - { |
1869 | - char *text = ((char *) frame->fr_data) + 1; |
1870 | - |
1871 | - while ( *text >= '0' && *text <= '9' ) { |
1872 | - number *= 10; |
1873 | - number += *text - '0'; |
1874 | - text++; |
1875 | - } |
1876 | + case ID3_ENCODING_ISO_8859_1: |
1877 | + { |
1878 | + char *text = ((char *) frame->fr_data) + 1; |
1879 | + |
1880 | + while ( *text >= '0' && *text <= '9' ) { |
1881 | + number *= 10; |
1882 | + number += *text - '0'; |
1883 | + text++; |
1884 | + } |
1885 | + |
1886 | + return number; |
1887 | + } |
1888 | + case ID3_ENCODING_UTF16: |
1889 | + { |
1890 | + char *text = ((char *) frame->fr_data) + 3; |
1891 | + |
1892 | +/* if (*(gint16 *) frame->fr_data == 0xfeff) */ |
1893 | +/* text++; */ |
1894 | + |
1895 | + while ( *text >= '0' && *text <= '9' ) { |
1896 | + number *= 10; |
1897 | + number += *text - '0'; |
1898 | + text++; |
1899 | + } |
1900 | |
1901 | - return number; |
1902 | - } |
1903 | - case ID3_ENCODING_UTF16: |
1904 | - { |
1905 | - char *text = ((char *) frame->fr_data) + 3; |
1906 | - |
1907 | -/* if (*(gint16 *) frame->fr_data == 0xfeff) */ |
1908 | -/* text++; */ |
1909 | - |
1910 | - while ( *text >= '0' && *text <= '9' ) { |
1911 | - number *= 10; |
1912 | - number += *text - '0'; |
1913 | - text++; |
1914 | - } |
1915 | + return number; |
1916 | + } |
1917 | |
1918 | - return number; |
1919 | - } |
1920 | - |
1921 | - default: |
1922 | - return -1; |
1923 | + default: |
1924 | + return -1; |
1925 | } |
1926 | } |
1927 | |
1928 | @@ -260,7 +260,7 @@ |
1929 | { |
1930 | /* Type check */ |
1931 | if ( frame->fr_desc->fd_idstr[0] != 'T' ) |
1932 | - return -1; |
1933 | + return -1; |
1934 | |
1935 | /* |
1936 | * Release memory occupied by previous data. |
1937 | @@ -289,6 +289,58 @@ |
1938 | } |
1939 | |
1940 | |
1941 | + |
1942 | + |
1943 | +char* id3_get_comm(struct id3_frame *frame) |
1944 | +{ |
1945 | + |
1946 | + /* Type check */ |
1947 | + if ( frame->fr_desc->fd_id != ID3_COMM ) |
1948 | + return NULL; |
1949 | + |
1950 | + /* Check if frame is compressed */ |
1951 | + if (id3_decompress_frame(frame) == -1) |
1952 | + return NULL; |
1953 | + |
1954 | + /* |
1955 | + * <Header for 'Comment', ID: "COMM"> |
1956 | + * Text encoding $xx |
1957 | + * Language $xx xx xx |
1958 | + * Short content descrip. <text string according to encoding> $00 (00) |
1959 | + * The actual text <full text string according to encoding> |
1960 | + * |
1961 | + * Skip language and short description. |
1962 | + */ |
1963 | + switch ( *(guint8 *) frame->fr_data ) { |
1964 | + case ID3_ENCODING_ISO_8859_1: |
1965 | + { |
1966 | + char *text = (char *) frame->fr_data + 4; |
1967 | + |
1968 | + while ( *text != 0 ) |
1969 | + text++; |
1970 | + |
1971 | + return g_strdup(++text); |
1972 | + } |
1973 | + case ID3_ENCODING_UTF16: |
1974 | + { |
1975 | + char *text16 = (char *) frame->fr_data + 4; |
1976 | + |
1977 | + while (*text16 != 0 || *(text16 + 1) != 0) |
1978 | + text16 += 2; |
1979 | + |
1980 | + return id3_utf16_to_ascii(text16 + 2); |
1981 | + } |
1982 | + default: |
1983 | + return NULL; |
1984 | + } |
1985 | + |
1986 | + if (*(guint8 *) frame->fr_data == ID3_ENCODING_ISO_8859_1) |
1987 | + return g_strdup((char *) frame->fr_data + 1); |
1988 | + else |
1989 | + return id3_utf16_to_ascii(((char *) frame->fr_data + 1)); |
1990 | +} |
1991 | + |
1992 | + |
1993 | /* |
1994 | * Function id3_set_text_number (frame, number) |
1995 | * |
1996 | @@ -304,25 +356,25 @@ |
1997 | |
1998 | /* Type check */ |
1999 | if ( frame->fr_desc->fd_idstr[0] != 'T' ) |
2000 | - return -1; |
2001 | + return -1; |
2002 | |
2003 | /* |
2004 | * Release memory occupied by previous data. |
2005 | */ |
2006 | id3_frame_clear_data(frame); |
2007 | - |
2008 | + |
2009 | /* |
2010 | * Create a string with a reversed number. |
2011 | */ |
2012 | pos = 0; |
2013 | while ( number > 0 && pos < 64 ) { |
2014 | - buf[pos++] = (number % 10) + '0'; |
2015 | - number /= 10; |
2016 | + buf[pos++] = (number % 10) + '0'; |
2017 | + number /= 10; |
2018 | } |
2019 | if ( pos == 64 ) |
2020 | - return -1; |
2021 | + return -1; |
2022 | if ( pos == 0 ) |
2023 | - buf[pos++] = '0'; |
2024 | + buf[pos++] = '0'; |
2025 | |
2026 | /* |
2027 | * Allocate memory for new data. |
2028 | @@ -336,7 +388,7 @@ |
2029 | *(gint8 *) frame->fr_raw_data = ID3_ENCODING_ISO_8859_1; |
2030 | text = (char *) frame->fr_raw_data + 1; |
2031 | while ( --pos >= 0 ) |
2032 | - *text++ = buf[pos]; |
2033 | + *text++ = buf[pos]; |
2034 | *text = '\0'; |
2035 | |
2036 | frame->fr_altered = 1; |
2037 | @@ -350,9 +402,9 @@ |
2038 | |
2039 | gboolean id3_frame_is_text(struct id3_frame *frame) |
2040 | { |
2041 | - if (frame && frame->fr_desc && |
2042 | - (frame->fr_desc->fd_idstr[0] == 'T' || |
2043 | - frame->fr_desc->fd_idstr[0] == 'W' )) |
2044 | - return TRUE; |
2045 | - return FALSE; |
2046 | + if (frame && frame->fr_desc && |
2047 | + (frame->fr_desc->fd_idstr[0] == 'T' || |
2048 | + frame->fr_desc->fd_idstr[0] == 'W' )) |
2049 | + return TRUE; |
2050 | + return FALSE; |
2051 | } |
2052 | diff -Naur xmms-1.2.9-orig/Input/mpg123/lib_id3v2.h xmms-1.2.9/Input/mpg123/lib_id3v2.h |
2053 | --- xmms-1.2.9-orig/Input/mpg123/lib_id3v2.h Wed Dec 31 19:00:00 1969 |
2054 | +++ xmms-1.2.9/Input/mpg123/lib_id3v2.h Thu Jan 29 05:20:31 2004 |
2055 | @@ -0,0 +1,1280 @@ |
2056 | +/* the id3v2.3 library. |
2057 | + * (c)2002 by Samuel Abels (sam@manicsadness.com) |
2058 | + * This project's homepage is: http://software.manicsadness.com/cantus |
2059 | + * |
2060 | + * This library is designed for easyest possible access to id3 V2 tags. |
2061 | + * |
2062 | + * This program is free software; you can redistribute it and/or modify |
2063 | + * it under the terms of the GNU General Public License as published by |
2064 | + * the Free Software Foundation; either version 2 of the License, or |
2065 | + * (at your option) any later version. |
2066 | + * |
2067 | + * This program is distributed in the hope that it will be useful, |
2068 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2069 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2070 | + * GNU General Public License for more details. |
2071 | + |
2072 | + * You should have received a copy of the GNU General Public License |
2073 | + * along with this program; if not, write to the Free Software |
2074 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
2075 | + */ |
2076 | + |
2077 | +#ifndef DLL_H |
2078 | +#define DLL_H |
2079 | +typedef struct DLL_s |
2080 | +{ |
2081 | + void *prev; |
2082 | + void *data; |
2083 | + void *next; |
2084 | +} DLL; |
2085 | +#endif |
2086 | + |
2087 | +#ifndef FALSE |
2088 | +#define FALSE 0 |
2089 | +#endif |
2090 | +#ifndef TRUE |
2091 | +#define TRUE 1 |
2092 | +#endif |
2093 | + |
2094 | +#ifndef id3Tag_def |
2095 | +#define id3Tag_def |
2096 | + |
2097 | +typedef struct id3Tag_s |
2098 | +{ |
2099 | + char title[1024]; |
2100 | + char artist[1024]; |
2101 | + char album[1024]; |
2102 | + char year[5]; |
2103 | + char comment[1024]; |
2104 | + char track[3]; |
2105 | + char genre[512]; |
2106 | + char composer[1024]; |
2107 | + char url[1024]; |
2108 | + char orig_artist[1024]; |
2109 | + char enc_by[1024]; |
2110 | + unsigned int size; |
2111 | + short int has_footer; |
2112 | +} id3Tag; |
2113 | + |
2114 | +typedef struct id3v2Tag_s |
2115 | +{ |
2116 | +// header |
2117 | + int tag_size; |
2118 | + short int unsync; |
2119 | + short int has_extheader; |
2120 | + short int is_experimental; |
2121 | +//extheader |
2122 | + int extheader_size; |
2123 | + int padding_size; |
2124 | + short int crc_data_present; |
2125 | + char crc_data[4]; |
2126 | +// frames |
2127 | + DLL *frames; |
2128 | +} id3v2Tag; |
2129 | + |
2130 | +typedef struct id3v2Frame_s |
2131 | +{ |
2132 | + unsigned char id[4]; |
2133 | + int datasize; |
2134 | + short int tagalter; |
2135 | + short int filealter; |
2136 | + short int readonly; |
2137 | + short int compression; |
2138 | + short int encryption; |
2139 | + short int grouping; |
2140 | + char *data; |
2141 | +} id3v2Frame; |
2142 | + |
2143 | +#endif |
2144 | + |
2145 | +/* the id3v2.3 library. |
2146 | + * (c)2002 by Samuel Abels (sam@manicsadness.com) |
2147 | + * This project's homepage is: http://software.manicsadness.com/cantus |
2148 | + * |
2149 | + * This library is designed for easyest possible access to id3 V2 tags. |
2150 | + * |
2151 | + * This program is free software; you can redistribute it and/or modify |
2152 | + * it under the terms of the GNU General Public License as published by |
2153 | + * the Free Software Foundation; either version 2 of the License, or |
2154 | + * (at your option) any later version. |
2155 | + * |
2156 | + * This program is distributed in the hope that it will be useful, |
2157 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2158 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2159 | + * GNU General Public License for more details. |
2160 | + |
2161 | + * You should have received a copy of the GNU General Public License |
2162 | + * along with this program; if not, write to the Free Software |
2163 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
2164 | + */ |
2165 | + |
2166 | +#include <stdio.h> |
2167 | +#include <string.h> |
2168 | +#include <stdlib.h> |
2169 | +#include <ctype.h> |
2170 | +#include "charset.h" |
2171 | + |
2172 | + |
2173 | + |
2174 | +/*************************************************************************************** |
2175 | + * BELOW FOLLOW THE STATICS |
2176 | + ***************************************************************************************/ |
2177 | +// Return the last item of an doubly linked list |
2178 | +static DLL * |
2179 | +dll_last (DLL *list) |
2180 | +{ |
2181 | + if( list == NULL ) |
2182 | + return (NULL); |
2183 | + |
2184 | + while ( list->next != NULL ) |
2185 | + list = list->next; |
2186 | + |
2187 | + return (list); |
2188 | +} |
2189 | + |
2190 | +// Append an item to the doubly linked list |
2191 | +static DLL * |
2192 | +dll_append (DLL *list, void *data) |
2193 | +{ |
2194 | + DLL *item = malloc (sizeof(DLL)); |
2195 | + DLL *lastitem = dll_last(list); |
2196 | + |
2197 | + item->data = data; |
2198 | + item->next = NULL; |
2199 | + |
2200 | + if ( lastitem == NULL ) |
2201 | + { |
2202 | + item->prev = NULL; |
2203 | + return (item); |
2204 | + } |
2205 | + else |
2206 | + { |
2207 | + item->prev = lastitem; |
2208 | + lastitem->next = item; |
2209 | + } |
2210 | + |
2211 | + return list; |
2212 | +} |
2213 | + |
2214 | +static DLL * |
2215 | +dll_remove (DLL *list, void *data) |
2216 | +{ |
2217 | + DLL *item = list; |
2218 | + |
2219 | + while ( item ) |
2220 | + { |
2221 | + if ( item->data == data ) |
2222 | + { |
2223 | + if ( item->prev == NULL |
2224 | + && item->next == NULL ) |
2225 | + { |
2226 | +// No other items there? Then return a zero pointer. |
2227 | + free (item); |
2228 | + return (NULL); |
2229 | + } |
2230 | + if ( item->prev == NULL ) |
2231 | + { |
2232 | +// remove the first item of the list here... |
2233 | + list = item->next; |
2234 | + list->prev = NULL; |
2235 | + free (item); |
2236 | + |
2237 | + break; |
2238 | + } |
2239 | + if ( item->next == NULL ) |
2240 | + { |
2241 | +// ...remove the last item of the list here... |
2242 | + ((DLL*)(item->prev))->next = NULL; |
2243 | + free (item); |
2244 | + |
2245 | + break; |
2246 | + } |
2247 | +// ...or other items here |
2248 | + ((DLL*)(item->prev))->next = item->next; |
2249 | + ((DLL*)(item->next))->prev = item->prev; |
2250 | + free (item); |
2251 | + |
2252 | + break; |
2253 | + } |
2254 | + item = item->next; |
2255 | + } |
2256 | + |
2257 | + return list; |
2258 | +} |
2259 | + |
2260 | +// Free a doubly linked list |
2261 | +static DLL * |
2262 | +dll_free (DLL *list) |
2263 | +{ |
2264 | + DLL *item = list; |
2265 | + DLL *current = NULL; |
2266 | + |
2267 | + while (item) |
2268 | + { |
2269 | + current = item; |
2270 | + item = item->next; |
2271 | + |
2272 | + free (current); |
2273 | + } |
2274 | + |
2275 | + return NULL; |
2276 | +} |
2277 | + |
2278 | +/* |
2279 | + * Converts all occurences of a CR/LF to LF |
2280 | + */ |
2281 | +static void |
2282 | +crlf2cr (char *source) |
2283 | +{ |
2284 | + char *psource = source; |
2285 | + char destination[2048]; |
2286 | + |
2287 | + if(source != NULL) |
2288 | + { |
2289 | + memset (destination, 0, 2048); |
2290 | + for (psource = source; *psource != '\0'; psource++) |
2291 | + { |
2292 | + if(*psource == 13 |
2293 | + && *(psource+1) == 10 ) |
2294 | + { |
2295 | + psource++; |
2296 | + } |
2297 | + destination[strlen(destination)] = *psource; |
2298 | + } |
2299 | + } |
2300 | + |
2301 | + strncpy (source, destination, strlen(destination)+1); |
2302 | +} |
2303 | + |
2304 | + |
2305 | +/* |
2306 | + * Converts all occurences of a LF to CR/LF |
2307 | + */ |
2308 | +static void |
2309 | +cr2crlf (char *source) |
2310 | +{ |
2311 | + char *psource = source; |
2312 | + char destination[2048]; |
2313 | + |
2314 | + if( source != NULL ) |
2315 | + { |
2316 | + memset (destination, 0, 2048); |
2317 | + for (psource = source; *psource != '\0'; psource++) |
2318 | + { |
2319 | + if (*psource == 10) |
2320 | + destination[strlen(destination)] = 13; |
2321 | + destination[strlen(destination)] = *psource; |
2322 | + } |
2323 | + } |
2324 | + |
2325 | + strncpy (source, destination, strlen(destination)+1); |
2326 | +} |
2327 | + |
2328 | + |
2329 | + |
2330 | + |
2331 | +/* |
2332 | + * Reads the first ten bytes of an file and checks, if it's a valid ID3 V2.3 file |
2333 | + * If it is, the header flags are stored in the tag struct. |
2334 | + * Returns TRUE on a valid header, otherwise FALSE. |
2335 | + */ |
2336 | +static short int |
2337 | +check_header (FILE *mp3file, id3v2Tag *v2) |
2338 | +{ |
2339 | + unsigned char buf[10]; |
2340 | + |
2341 | +// get header (=first ten bytes of the file) |
2342 | + fseek (mp3file, 0, SEEK_SET); |
2343 | + if ( fread (buf, 1, 10, mp3file) < 10 ) |
2344 | + return (FALSE); |
2345 | + |
2346 | +// a valid tag must begin with "ID3" followed by the version (checked below) |
2347 | +// followed by a flag byte, where the last five bytes are unused and must be FALSE |
2348 | + if ( memcmp(buf, "ID3", 3) != 0 |
2349 | + || (buf[5] & 31) != 0 ) |
2350 | + return (FALSE); |
2351 | + |
2352 | +// check if version is supported |
2353 | + if ( buf[3] != 3 |
2354 | + || buf[4] != 0 ) |
2355 | + return (FALSE); |
2356 | + |
2357 | +// The next thing to come is the tag size. These are 4 bytes, the MSB should always be set to zero. check! |
2358 | + if ( (buf[6] & 128) != 0 |
2359 | + || (buf[7] & 128) != 0 |
2360 | + || (buf[8] & 128) != 0 |
2361 | + || (buf[9] & 128) != 0 ) |
2362 | + return (FALSE); |
2363 | + |
2364 | +// The tag size is encoded to be syncsave, so I got to decode it. |
2365 | +// The tag size is the size of the complete tag EXCLUDING the 10-byte header. |
2366 | + v2->tag_size = buf[9] + (buf[8] << 7) + (buf[7] << 14) + (buf[6] << 21); |
2367 | + |
2368 | +// ok, so were save. put the flags in the nicer struct. |
2369 | + v2->unsync = (buf[5] & 128) >> 7; |
2370 | + v2->has_extheader = (buf[5] & 64) >> 6; |
2371 | + v2->is_experimental = (buf[5] & 32) >> 5; |
2372 | + |
2373 | + return (TRUE); |
2374 | +} |
2375 | + |
2376 | + |
2377 | + |
2378 | + |
2379 | + |
2380 | +/* |
2381 | + * Reads the extheader of a valid ID3V2.3 file and checks, if it's a valid. |
2382 | + * If it is, the extheader flags are stored in the tag struct. |
2383 | + * Returns TRUE on a valid extheader, otherwise FALSE. |
2384 | + */ |
2385 | +static short int |
2386 | +check_extheader (FILE *mp3file, id3v2Tag *v2) |
2387 | +{ |
2388 | + unsigned char buf[10]; |
2389 | + |
2390 | +// Read id3 extheader intro (5 bytes) |
2391 | + fseek (mp3file, 10, SEEK_SET); |
2392 | + if ( fread(buf, 1, 5, mp3file) < 5 ) |
2393 | + return (FALSE); |
2394 | + |
2395 | +// First comes the extheader size. These are 4 bytes, the MSB should always be set to zero. check! |
2396 | + if( (buf[0] & 128) != 0 |
2397 | + || (buf[1] & 128) != 0 |
2398 | + || (buf[2] & 128) != 0 |
2399 | + || (buf[3] & 128) != 0 ) |
2400 | + return (FALSE); |
2401 | + |
2402 | +// OK. In ID3V2.3 only six byte or ten byte extheaders are allowed. |
2403 | + if( v2->extheader_size != 6 |
2404 | + && v2->extheader_size != 10 ) |
2405 | + return (FALSE); |
2406 | + |
2407 | +// The first four bytes specify the extheader size. |
2408 | + v2->extheader_size = buf[3] + (buf[2] << 7) + (buf[1] << 14) + (buf[0] << 21); |
2409 | + |
2410 | +// The fifth byte specifies extendened flags. (in fact, only one flag is used for ID3V2.3 |
2411 | +// The MSB of the byte 5 specifies, if there is CRC data to come, appended to the extheader. |
2412 | + if( (buf[4] & 127) != 0 |
2413 | + || buf[5] != 0 ) |
2414 | + return (FALSE); |
2415 | + |
2416 | + v2->crc_data_present = (buf[4] & 128) >> 7; |
2417 | + |
2418 | +// if crc data is present, the extheader size must be ten bytes, otherwise 6. |
2419 | + if ( (v2->extheader_size == 6 && v2->crc_data_present == TRUE) |
2420 | + || (v2->extheader_size == 10 && v2->crc_data_present == FALSE) ) |
2421 | + return (FALSE); |
2422 | + |
2423 | +// now come four bytes specifying the padding size |
2424 | + if ( (buf[6] & 128) != 0 |
2425 | + || (buf[7] & 128) != 0 |
2426 | + || (buf[8] & 128) != 0 |
2427 | + || (buf[9] & 128) != 0 ) |
2428 | + return (FALSE); |
2429 | + |
2430 | + v2->padding_size = buf[9] + (buf[8] << 7) + (buf[7] << 14) + (buf[6] << 21); |
2431 | + |
2432 | +// Now to the optional crc data. |
2433 | + if( v2->crc_data_present ) |
2434 | + { |
2435 | + if( fread (buf, 1, 4, mp3file) < 4 ) |
2436 | + return (FALSE); |
2437 | + |
2438 | + memcpy (v2->crc_data, buf, 4); |
2439 | + } |
2440 | + |
2441 | + return (TRUE); |
2442 | +} |
2443 | + |
2444 | + |
2445 | + |
2446 | + |
2447 | + |
2448 | +/* |
2449 | + * Reads the complete frames of a valid ID3V2.3 file and checks, if they are valid. |
2450 | + * If they are, the flags are stored in a DLL and appended to the tag struct. |
2451 | + * Returns TRUE on success, otherwise FALSE. |
2452 | + */ |
2453 | +static short int |
2454 | +read_frames (FILE *mp3file, id3v2Tag *v2) |
2455 | +{ |
2456 | + unsigned char buf[10]; |
2457 | + int numframes = 0; |
2458 | + unsigned int totalframesize = 0; |
2459 | + id3v2Frame *frame = NULL; |
2460 | + |
2461 | +// set the position to the first frame header (header = 10 bytes + extheadersize + 4 bytes "extheaderheader") |
2462 | + if (v2->has_extheader) |
2463 | + fseek (mp3file, 10 + v2->extheader_size + 4, SEEK_SET); |
2464 | + else |
2465 | + fseek (mp3file, 10, SEEK_SET); |
2466 | + |
2467 | +// If the tag size is too small for frames, return with an error. |
2468 | + if ( ((v2->tag_size + 10) - v2->padding_size) <= ftell(mp3file) ) |
2469 | + return FALSE; |
2470 | + |
2471 | +// now read all the frames |
2472 | + numframes = 0; |
2473 | + v2->frames = NULL; |
2474 | + while ( ftell (mp3file) < ((v2->tag_size + 10) - v2->padding_size) ) |
2475 | + { |
2476 | + frame = calloc (1, sizeof(id3v2Frame)); |
2477 | + |
2478 | +// the frame header is ten bytes long |
2479 | + if ( fread (buf, 1, 10, mp3file) < 10 ) |
2480 | + goto error; |
2481 | + |
2482 | +// if we are already in the padding, we must no longer look for frames... |
2483 | + if ( buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0 ) |
2484 | + { |
2485 | + if (numframes == 0) |
2486 | + goto error; |
2487 | + |
2488 | + free (frame); |
2489 | + break; |
2490 | + } |
2491 | + |
2492 | +// first come four characters identifying the frame. It must be alphanumeric. |
2493 | + if ( !isalnum(buf[0]) || !isalnum(buf[1]) || !isalnum(buf[2]) || !isalnum(buf[3]) ) |
2494 | + goto error; |
2495 | + |
2496 | + *(frame->id) = buf[0]; |
2497 | + *(frame->id + 1) = buf[1]; |
2498 | + *(frame->id + 2) = buf[2]; |
2499 | + *(frame->id + 3) = buf[3]; |
2500 | + |
2501 | +// then, the frame size is to come. Again, the four MSBs must be zero. |
2502 | + if ( (buf[4] & 128) != 0 |
2503 | + || (buf[5] & 128) != 0 |
2504 | + || (buf[6] & 128) != 0 |
2505 | + || (buf[7] & 128) != 0 ) |
2506 | + goto error; |
2507 | + |
2508 | + frame->datasize = buf[7] + (buf[6] << 7) + (buf[5] << 14) + (buf[4] << 21); |
2509 | + |
2510 | +// A minimum size must be present! |
2511 | + if ( frame->datasize <= 0 ) |
2512 | + goto error; |
2513 | + |
2514 | +// The two following frame header flags have the 5 LSBs not set. |
2515 | + if ( (buf[8] & 31) != 0 |
2516 | + || (buf[9] & 31) != 0 ) |
2517 | + goto error; |
2518 | + |
2519 | +// now, put the flags in the struct. |
2520 | + frame->tagalter = (buf[8] & 128) >> 7; |
2521 | + frame->filealter = (buf[8] & 64) >> 6; |
2522 | + frame->readonly = (buf[8] & 32) >> 5; |
2523 | + |
2524 | + frame->compression = (buf[9] & 128) >> 7; |
2525 | + frame->encryption = (buf[8] & 64) >> 6; |
2526 | + frame->grouping = (buf[8] & 32) >> 5; |
2527 | + |
2528 | +// ok, we are done with the frame header, so now we read the frame data. |
2529 | + frame->data = calloc (1, frame->datasize + 1); |
2530 | + if( fread (frame->data, 1, frame->datasize, mp3file) < frame->datasize ) |
2531 | + goto error; |
2532 | + |
2533 | + numframes++; |
2534 | + totalframesize += 10 + frame->datasize; |
2535 | + |
2536 | +// we append it to a glist, which is appended to the v2 struct. |
2537 | + v2->frames = dll_append (v2->frames, frame); |
2538 | + } |
2539 | + |
2540 | +// if we have no extheader, that means, we don't know how much padding we have! |
2541 | +// thus, i calculate it here. |
2542 | + if ( !v2->has_extheader ) |
2543 | + v2->padding_size = v2->tag_size - totalframesize; |
2544 | + |
2545 | +// A minimum of one frame is mandatory. |
2546 | + if( numframes > 0 ) |
2547 | + return (TRUE); |
2548 | + |
2549 | +error: |
2550 | +// cleanups in case of an error. |
2551 | + if( frame && frame->data ) |
2552 | + free (frame->data); |
2553 | + if( frame ) |
2554 | + free (frame); |
2555 | + return (FALSE); |
2556 | +} |
2557 | + |
2558 | + |
2559 | + |
2560 | + |
2561 | + |
2562 | + |
2563 | + |
2564 | + |
2565 | + |
2566 | + |
2567 | + |
2568 | + |
2569 | + |
2570 | + |
2571 | + |
2572 | +/* |
2573 | + * Reads all tag information of a valid ID3V2.3 file. |
2574 | + * When successful, the info is stored in the tag struct. |
2575 | + * Returns: |
2576 | + * 0 = success |
2577 | + * 1 = Cannot open file. |
2578 | + * 2 = No header or wrong version. |
2579 | + * 3 = broken extheader. |
2580 | + * 4 = broken frames. |
2581 | + */ |
2582 | +static int |
2583 | +get_id3v2tag_raw (id3v2Tag *v2, char *filename) |
2584 | +{ |
2585 | + FILE *mp3file = NULL; |
2586 | + int error = 0; |
2587 | + |
2588 | +// open file |
2589 | + error = 1; |
2590 | + mp3file = fopen (filename, "rb"); |
2591 | + if (!mp3file) |
2592 | + goto done; |
2593 | + |
2594 | +// check/get header |
2595 | + error = 2; |
2596 | + if( !check_header (mp3file, v2) ) |
2597 | + goto done; |
2598 | + |
2599 | +// check/get extheader |
2600 | + error = 3; |
2601 | + if( v2->has_extheader |
2602 | + && !check_extheader (mp3file, v2) ) |
2603 | + goto done; |
2604 | + |
2605 | +// get the content frames |
2606 | + error = 4; |
2607 | + if( !read_frames (mp3file, v2) ) |
2608 | + goto done; |
2609 | + |
2610 | + error = 0; |
2611 | +done: |
2612 | + fclose (mp3file); |
2613 | + return (error); |
2614 | +} |
2615 | + |
2616 | + |
2617 | + |
2618 | + |
2619 | + |
2620 | +/* |
2621 | + * Find one frames data and give back its data in the correct format. |
2622 | + * Returns TRUE on success, otherwise FALSE; |
2623 | + */ |
2624 | +static short int |
2625 | +frame_find (id3v2Tag *v2, char *name, char *value) |
2626 | +{ |
2627 | + DLL *curframe = NULL; |
2628 | + id3v2Frame *frame = NULL; |
2629 | + |
2630 | + // we parse through the whole list of frames, giving back the correct frame value. |
2631 | + curframe = v2->frames; |
2632 | + while ( curframe ) |
2633 | + { |
2634 | + frame = (id3v2Frame *)curframe->data; |
2635 | + |
2636 | + // Just to be sure... |
2637 | + if( frame->datasize <= 0 ) |
2638 | + goto nextframe; |
2639 | + |
2640 | + // Matches the users request? Otherwise try the next frame. |
2641 | + if( memcmp (frame->id, name, 4) != 0 ) |
2642 | + goto nextframe; |
2643 | + |
2644 | + // These types don't need much change, just give the whole data back to the user according to the encoding. |
2645 | + // The first byte is the encoding. |
2646 | + // TPE1: Artist |
2647 | + // TIT2: Song Title |
2648 | + // TALB: Album Title |
2649 | + // TYER: Year |
2650 | + // TRCK: Track |
2651 | + // TCON: Genre |
2652 | + // COMM: Comment |
2653 | + // TCOM: Composer |
2654 | + // TOPE: TOPE Original artist(s)/performer(s) |
2655 | + // TENC: Encoded by |
2656 | + if ( memcmp (frame->id, "TPE1", 4) == 0 |
2657 | + || memcmp (frame->id, "TIT2", 4) == 0 |
2658 | + || memcmp (frame->id, "TALB", 4) == 0 |
2659 | + || memcmp (frame->id, "TYER", 4) == 0 |
2660 | + || memcmp (frame->id, "TRCK", 4) == 0 |
2661 | + || memcmp (frame->id, "TCON", 4) == 0 |
2662 | + || memcmp (frame->id, "TCOM", 4) == 0 |
2663 | + || memcmp (frame->id, "TOPE", 4) == 0 |
2664 | + || memcmp (frame->id, "TENC", 4) == 0) |
2665 | + //|| memcmp (frame->id, "WXXX", 4) == 0) |
2666 | + { |
2667 | + if ( *frame->data == 0 ) |
2668 | + memcpy(value, frame->data + 1, frame->datasize - 1); |
2669 | + if ( *frame->data == 1 ) |
2670 | + { |
2671 | + char nulltermvalue[frame->datasize]; |
2672 | + char *isovalue = NULL; |
2673 | + |
2674 | + // the tag is not null terminated, so i have to create a null terminated string first. |
2675 | + memset (nulltermvalue, 0, frame->datasize); |
2676 | + memcpy (nulltermvalue, frame->data + 1, frame->datasize - 1); |
2677 | + |
2678 | + // Convert from UTF to ISO and copy to the users variable. |
2679 | + isovalue = convert_from_utf8 (nulltermvalue); |
2680 | + strncpy (value, isovalue, sizeof(value) - 1); |
2681 | + free (isovalue); |
2682 | + } |
2683 | + |
2684 | + // change linefeeds to a single "return" key. |
2685 | + crlf2cr (value); |
2686 | + return (TRUE); |
2687 | + } |
2688 | + if ( memcmp (frame->id, "WCOM", 4) == 0 |
2689 | + || memcmp (frame->id, "WCOP", 4) == 0 |
2690 | + || memcmp (frame->id, "WOAF", 4) == 0 |
2691 | + || memcmp (frame->id, "WOAR", 4) == 0 |
2692 | + || memcmp (frame->id, "WOAS", 4) == 0 |
2693 | + || memcmp (frame->id, "WPAY", 4) == 0 |
2694 | + || memcmp (frame->id, "WPUB", 4) == 0) |
2695 | + { |
2696 | + memcpy(value, frame->data, frame->datasize - 1); |
2697 | + |
2698 | + // change linefeeds to a single "return" key. |
2699 | + crlf2cr (value); |
2700 | + return (TRUE); |
2701 | + } |
2702 | + |
2703 | + // The comment requires special handling. |
2704 | + // Its data has: One byte "encoding" (0 = ISO-8859-1, 1 = UNICODE) |
2705 | + // followed by the language (three bytes, e.g. "eng"), |
2706 | + // followed by a short description, |
2707 | + // then a NULL, |
2708 | + // and the full description |
2709 | + // For now, i simply drop the short description |
2710 | + if( memcmp(frame->id, "COMM", 4) == 0 ) |
2711 | + { |
2712 | + // check for the right format. (minsize 5, must contain a "\0" after the language) |
2713 | + if ( frame->datasize < 5 ) |
2714 | + goto nextframe; |
2715 | + if ( !memchr (frame->data + 4, '\0', frame->datasize - 4) ) |
2716 | + goto nextframe; |
2717 | + |
2718 | + // now, give the data back to the user, according to the encoding. |
2719 | + if ( *frame->data == 0 ) |
2720 | + memcpy (value, frame->data + 5, frame->datasize - 5); |
2721 | + if ( *frame->data == 1 ) |
2722 | + { |
2723 | + char nulltermvalue[frame->datasize]; |
2724 | + char *isovalue = NULL; |
2725 | + |
2726 | + // the tag is not null terminated, so i have to create a null terminated string first. |
2727 | + memset (nulltermvalue, 0, frame->datasize); |
2728 | + memcpy (nulltermvalue, frame->data + 5, frame->datasize - 5); |
2729 | + |
2730 | + // Convert from UTF to ISO and copy to the users variable. |
2731 | + isovalue = convert_from_utf8 (nulltermvalue); |
2732 | + strncpy (value, isovalue, sizeof(value) - 1); |
2733 | + free (isovalue); |
2734 | + } |
2735 | + |
2736 | + // change linefeeds to a single "return" key. |
2737 | + crlf2cr (value); |
2738 | + return TRUE; |
2739 | + } |
2740 | + |
2741 | +nextframe: |
2742 | + curframe = curframe->next; |
2743 | + } |
2744 | + |
2745 | + return FALSE; |
2746 | +} |
2747 | + |
2748 | + |
2749 | + |
2750 | + |
2751 | +/* |
2752 | + * Remove one frame out of the id3v2Tag struct |
2753 | + * Returns TRUE on success, otherwise FALSE; |
2754 | + */ |
2755 | +static short int |
2756 | +frame_remove (id3v2Tag *v2, char *name) |
2757 | +{ |
2758 | + id3v2Frame *frame = NULL; |
2759 | + DLL *curframe = NULL; |
2760 | + DLL *tempframe = NULL; |
2761 | + |
2762 | +// Parse through the list of frames. |
2763 | + curframe = v2->frames; |
2764 | + while ( curframe ) |
2765 | + { |
2766 | + frame = (id3v2Frame *)curframe->data; |
2767 | + tempframe = curframe; |
2768 | + curframe = curframe->next; |
2769 | + |
2770 | + if ( memcmp (frame->id, name, 4) == 0 ) |
2771 | + { |
2772 | +// we have found the item! removing will NOT shrink the tag, but increase the padding. |
2773 | + v2->padding_size += (frame->datasize + 10); |
2774 | +// and free memory. |
2775 | + v2->frames = dll_remove (v2->frames, tempframe->data); |
2776 | + free (frame->data); |
2777 | + free (frame); |
2778 | + |
2779 | + return TRUE; |
2780 | + } |
2781 | + } |
2782 | + |
2783 | + return FALSE; |
2784 | +} |
2785 | + |
2786 | + |
2787 | + |
2788 | +/* |
2789 | + * Add a frame to the framelist. If the frame name is already in the list, it will be replaced. |
2790 | + * Returns: |
2791 | + * TRUE: The tag size HAS BEEN increased. |
2792 | + * FALSE: The tag size has NOT been increased. |
2793 | + */ |
2794 | +static short int |
2795 | +frame_set (id3v2Tag *v2, char *name, char *value) |
2796 | +{ |
2797 | + id3v2Frame *frame = NULL; |
2798 | + short int sizechange = FALSE; |
2799 | + |
2800 | +// prevent the user to send CR/LF, which is forbidden. |
2801 | + cr2crlf (value); |
2802 | +// eventually remove an existing item! |
2803 | + frame_remove (v2, name); |
2804 | + |
2805 | +// alloc space for the new frame. |
2806 | + frame = malloc (sizeof(id3v2Frame)); |
2807 | + |
2808 | + memcpy (frame->id, name, 4); |
2809 | + frame->datasize = strlen (value); |
2810 | + frame->tagalter = 0; |
2811 | + frame->filealter = 0; |
2812 | + frame->readonly = 0; |
2813 | + frame->compression = 0; |
2814 | + frame->encryption = 0; |
2815 | + frame->grouping = 0; |
2816 | + |
2817 | +// The comment requires special handling. If you need to know why, look at the documentation |
2818 | +// of the "frame_find" function above. |
2819 | + if( memcmp (frame->id, "COMM", 4) == 0 ) |
2820 | + { |
2821 | + char fullvalue[frame->datasize + 6]; |
2822 | + |
2823 | + sprintf(fullvalue, "%ceng%c%s", 0, 0, value); |
2824 | + |
2825 | + frame->datasize += 5; |
2826 | + frame->data = malloc (frame->datasize); |
2827 | + memcpy (frame->data, fullvalue, frame->datasize); |
2828 | + } |
2829 | + else if ((memcmp(frame->id, "WCOM", 4) == 0) |
2830 | + || memcmp (frame->id, "WCOP", 4) == 0 |
2831 | + || memcmp (frame->id, "WOAF", 4) == 0 |
2832 | + || memcmp (frame->id, "WOAR", 4) == 0 |
2833 | + || memcmp (frame->id, "WOAS", 4) == 0 |
2834 | + || memcmp (frame->id, "WPAY", 4) == 0 |
2835 | + || memcmp (frame->id, "WPUB", 4) == 0) |
2836 | + { |
2837 | + frame->data = malloc (frame->datasize); |
2838 | + memcpy (frame->data, value, frame->datasize); |
2839 | + } |
2840 | + else |
2841 | + { |
2842 | + char fullvalue[frame->datasize + 2]; |
2843 | + |
2844 | + // Put encoding type just before the value |
2845 | + sprintf (fullvalue, "%c%s", 0, value); |
2846 | + |
2847 | + frame->datasize += 1; |
2848 | + frame->data = malloc (frame->datasize); |
2849 | + memcpy (frame->data, fullvalue, frame->datasize); |
2850 | + } |
2851 | + |
2852 | +// Ok. This decreases the available padding. If we have no padding left, we must increase the padding (and thus, the tag). |
2853 | + if( v2->padding_size - (frame->datasize + 10) <= 0 ) |
2854 | + { |
2855 | +// add: framesize + frameheadersize + padding. |
2856 | + v2->padding_size += frame->datasize + 10 + 1024; |
2857 | + v2->tag_size += frame->datasize + 10 + 1024; |
2858 | + |
2859 | + sizechange = TRUE; |
2860 | + } |
2861 | + |
2862 | +// In every case, we must subtract the new allocated space from the padding. |
2863 | + v2->padding_size -= frame->datasize + 10; |
2864 | + |
2865 | + v2->frames = dll_append (v2->frames, frame); |
2866 | + |
2867 | + return sizechange; |
2868 | +} |
2869 | + |
2870 | + |
2871 | + |
2872 | +/* |
2873 | + * Create raw header. |
2874 | + * Returns: |
2875 | + * TRUE: successful. |
2876 | + * FALSE: unsuccessful. |
2877 | + */ |
2878 | +static int |
2879 | +create_header_raw (char *raw, id3v2Tag *v2) |
2880 | +{ |
2881 | +// now we are going to write the tags raw data into the raw string |
2882 | + memset (raw, 0, v2->tag_size + 10); |
2883 | +// ID3 identifier bytes |
2884 | + memcpy (raw, "ID3", 3); |
2885 | + raw += 3; |
2886 | +// major version byte |
2887 | + *raw++ = 3; |
2888 | +// minor version byte |
2889 | + *raw++ = 0; |
2890 | +// Flags byte |
2891 | + *raw++ = ((v2->unsync & 1) << 7) |
2892 | + | ((v2->has_extheader & 1) << 6) |
2893 | + | ((v2->is_experimental & 1) << 5); |
2894 | +// Tag size. It must be syncsafe! |
2895 | + *raw++ = ((v2->tag_size & 0x800000) >> 23) | (((v2->tag_size & 0x7f000000) >> 24) << 1); |
2896 | + *raw++ = ((v2->tag_size & 0x8000) >> 15) | (((v2->tag_size & 0x7f0000) >> 16) << 1); |
2897 | + *raw++ = ((v2->tag_size & 0x80) >> 7) | (((v2->tag_size & 0x7f00) >> 8) << 1); |
2898 | + *raw++ = (v2->tag_size & 0x7f); |
2899 | + |
2900 | + return TRUE; |
2901 | +} |
2902 | + |
2903 | + |
2904 | + |
2905 | + |
2906 | +/* |
2907 | + * Generates the frames. btw.: ID3 sucks! |
2908 | + * Returns: TRUE if succesful, otherwise FALSE. |
2909 | + */ |
2910 | +static short int |
2911 | +create_frames_raw (char *raw, id3v2Tag *v2) |
2912 | +{ |
2913 | + id3v2Frame *frame = NULL; |
2914 | + DLL *curframe = NULL; |
2915 | + |
2916 | +// if we have no frames, just quit. |
2917 | + if ( v2->frames == NULL ) |
2918 | + return FALSE; |
2919 | + |
2920 | +// the header and extheader have already been written. |
2921 | + raw += 10; |
2922 | + if ( v2->has_extheader ) |
2923 | + raw += 4 + v2->extheader_size; |
2924 | + |
2925 | + curframe = v2->frames; |
2926 | + while ( curframe ) |
2927 | + { |
2928 | + frame = (id3v2Frame *)curframe->data; |
2929 | + |
2930 | +// secure is secure |
2931 | + if ( frame->datasize <= 0 ) |
2932 | + goto nextframe; |
2933 | + |
2934 | +// add the frame id |
2935 | + memcpy(raw, frame->id, 4); |
2936 | + raw += 4; |
2937 | +// add the frame size (syncsafe) |
2938 | + *raw++ = ((frame->datasize & 0x800000) >> 23) | (((frame->datasize & 0x7f000000) >> 24) << 1); |
2939 | + *raw++ = ((frame->datasize & 0x8000) >> 15) | (((frame->datasize & 0x7f0000) >> 16) << 1); |
2940 | + *raw++ = ((frame->datasize & 0x80) >> 7) | (((frame->datasize & 0x7f00) >> 8) << 1); |
2941 | + *raw++ = (frame->datasize & 0x7f); |
2942 | + |
2943 | +// The two flagbytes |
2944 | + *raw++ = ((frame->tagalter & 1) << 7) |
2945 | + | ((frame->filealter & 1) << 6) |
2946 | + | ((frame->readonly & 1) << 5); |
2947 | + |
2948 | + *raw++ = ((frame->compression & 1) << 7) |
2949 | + | ((frame->encryption & 1) << 6) |
2950 | + | ((frame->grouping & 1) << 5); |
2951 | + |
2952 | +// now the frame data. |
2953 | + memcpy(raw, frame->data, frame->datasize); |
2954 | + raw += frame->datasize; |
2955 | + |
2956 | +nextframe: |
2957 | + curframe = curframe->next; |
2958 | + } |
2959 | + |
2960 | + return TRUE; |
2961 | +} |
2962 | + |
2963 | +/*************************************************************************************** |
2964 | + * END OF STATICS |
2965 | + ***************************************************************************************/ |
2966 | + |
2967 | + |
2968 | + |
2969 | + |
2970 | + |
2971 | + |
2972 | + |
2973 | +/* |
2974 | + * Purpose: Reads the ID3 tag from a file. |
2975 | + * Parameters: tag - The structure to store the tag in, filename - The name of the file to operate on. |
2976 | + * Returns: |
2977 | + * 0 if successful, |
2978 | + * 1 if an error occured when opening the file |
2979 | + * 2 if error while reading tag. |
2980 | + * 3 if no TAG found. |
2981 | + */ |
2982 | +int |
2983 | +get_id3v2_tag (id3Tag *tag, char *filename) |
2984 | +{ |
2985 | + id3v2Tag *v2 = calloc (1, sizeof(id3v2Tag)); |
2986 | + DLL *curframe = NULL; |
2987 | + int error = 0; |
2988 | + |
2989 | +// Read the tag. |
2990 | + error = get_id3v2tag_raw (v2, filename); |
2991 | + |
2992 | +// Init the users tag |
2993 | + memset (tag, 0, sizeof (id3Tag)); |
2994 | + |
2995 | + if( error == 0 ) |
2996 | + { |
2997 | +// if we have a valid tag we copy the raw data to the users struct |
2998 | + tag->size = v2->tag_size; |
2999 | + |
3000 | + frame_find (v2, "TPE1", tag->artist); |
3001 | + frame_find (v2, "TIT2", tag->title); |
3002 | + frame_find (v2, "TALB", tag->album); |
3003 | + frame_find (v2, "TYER", tag->year); |
3004 | + frame_find (v2, "COMM", tag->comment); |
3005 | + frame_find (v2, "TRCK", tag->track); |
3006 | + frame_find (v2, "TCON", tag->genre); |
3007 | + frame_find (v2, "TCOM", tag->composer); // Composer |
3008 | + frame_find (v2, "TOPE", tag->orig_artist); // Original artist(s)/performer(s) |
3009 | + frame_find (v2, "WCOM", tag->url); // URL |
3010 | + frame_find (v2, "TENC", tag->enc_by); // Encoded by |
3011 | + } |
3012 | + |
3013 | +// Free all the stuff |
3014 | + if (v2->frames) |
3015 | + { |
3016 | + id3v2Frame *frame = NULL; |
3017 | + |
3018 | + curframe = v2->frames; |
3019 | + while ( curframe ) |
3020 | + { |
3021 | + frame = (id3v2Frame *)curframe->data; |
3022 | + |
3023 | + free (frame->data); |
3024 | + free (frame); |
3025 | + |
3026 | + curframe = curframe->next; |
3027 | + } |
3028 | + v2->frames = dll_free (v2->frames); |
3029 | + } |
3030 | + |
3031 | + free (v2); |
3032 | + return (error); |
3033 | +} |
3034 | + |
3035 | + |
3036 | + |
3037 | + |
3038 | + |
3039 | + |
3040 | + |
3041 | + |
3042 | + |
3043 | +/* |
3044 | + * Purpose: Clear the ID3 tag of a file. |
3045 | + * Parameters: a filename. |
3046 | + * Returns: |
3047 | + * 0 if successful, |
3048 | + * 1 if an error occured when opening the file |
3049 | + * 2 if an error while reading/writing the tag. |
3050 | + */ |
3051 | +int |
3052 | +del_id3v2_tag (char *filename) |
3053 | +{ |
3054 | + id3v2Tag *v2 = calloc (1, sizeof(id3v2Tag)); |
3055 | + long file_len; |
3056 | + FILE *file; |
3057 | + void *ptr; |
3058 | + |
3059 | +// check if an valid old id3v2 tag is present |
3060 | +// In these two error-cases we don't know how big the tag is. |
3061 | + if( get_id3v2tag_raw (v2, filename) == 1 |
3062 | + || get_id3v2tag_raw (v2, filename) == 2 ) |
3063 | + return(0); |
3064 | + |
3065 | + ptr = malloc (4096); |
3066 | + |
3067 | +// open file read/write |
3068 | + file = fopen (filename, "r+b"); |
3069 | + if (!file) |
3070 | + return (1); |
3071 | + |
3072 | + fseek (file, 0, SEEK_END); |
3073 | + file_len = ftell (file); |
3074 | + if ( file_len < 11 |
3075 | + || v2->tag_size < 11 ) |
3076 | + return (2); |
3077 | + |
3078 | +// set anything but the header in tag to zero. I'll not really remove the tag, |
3079 | +// because this would be much slower and if we write a new tag, this would mean we´d have to |
3080 | +// rewrite the complete tag. |
3081 | +/* |
3082 | + fseek (file, 10, SEEK_SET); |
3083 | + for (read = 0; read < v2->tag_size - 10; read++) |
3084 | + fputc (0, file); |
3085 | + |
3086 | +*/ |
3087 | + { |
3088 | + FILE *file = NULL; |
3089 | + FILE *tempfile = NULL; |
3090 | + char *tempfilename = NULL; |
3091 | + int read = 0; |
3092 | + char buf[4096]; |
3093 | + int error = 0; |
3094 | + |
3095 | + // Open a tempfile |
3096 | + error = 2; |
3097 | + tempfilename = malloc (strlen (filename) + 11); |
3098 | + sprintf (tempfilename, "%s%s", filename, ".tempXXXXX"); |
3099 | + if( !(tempfile = fopen(tempfilename, "wb")) ) |
3100 | + { |
3101 | + remove (tempfilename); |
3102 | + free (tempfilename); |
3103 | + goto done; |
3104 | + } |
3105 | + |
3106 | + // Write the tag to the tempfile. |
3107 | + |
3108 | + // Open the mp3file. |
3109 | + error = 4; |
3110 | + if( !(file = fopen(filename, "r+b")) ) |
3111 | + { |
3112 | + fclose (file); |
3113 | + remove (tempfilename); |
3114 | + free (tempfilename); |
3115 | + goto done; |
3116 | + } |
3117 | + // skip the old tag (if one existed) |
3118 | + fseek (file, v2->tag_size + 10, SEEK_SET); |
3119 | + |
3120 | + // copy the rest of the file to the tempfile. |
3121 | + while ( !feof(file) ) |
3122 | + { |
3123 | + error = 5; |
3124 | + read = fread (buf, 1, 4096, file); |
3125 | + if( fwrite (buf, 1, read, tempfile) != read |
3126 | + && !feof (file) ) |
3127 | + { |
3128 | + remove (tempfilename); |
3129 | + free (tempfilename); |
3130 | + fflush (tempfile); |
3131 | + fclose (tempfile); |
3132 | + fflush (file); |
3133 | + fclose (file); |
3134 | + goto done; |
3135 | + } |
3136 | + } |
3137 | + |
3138 | + fflush (file); |
3139 | + fclose (file); |
3140 | + fflush (tempfile); |
3141 | + fclose (tempfile); |
3142 | + |
3143 | + // rename the tempfile, so it is the mp3file. |
3144 | + rename (tempfilename, filename); |
3145 | + free (tempfilename); |
3146 | + } |
3147 | + |
3148 | +done: |
3149 | + if (v2) free (v2); |
3150 | + if (ptr) free (ptr); |
3151 | + |
3152 | + return(0); |
3153 | +} |
3154 | + |
3155 | + |
3156 | + |
3157 | + |
3158 | + |
3159 | + |
3160 | + |
3161 | + |
3162 | + |
3163 | + |
3164 | + |
3165 | +int |
3166 | +set_id3v2_tag (id3Tag *tag, char *filename) |
3167 | +{ |
3168 | + id3v2Tag *v2 = malloc (sizeof(id3v2Tag)); |
3169 | + id3v2Frame *frame = NULL; |
3170 | + unsigned char *rawdata = NULL; |
3171 | + DLL *curframe = NULL; |
3172 | + int oldsize = 0; |
3173 | + char track[3]; |
3174 | + int error = 0; |
3175 | + |
3176 | +// Try to get the content of an old tag |
3177 | + error = 1; |
3178 | + memset (v2, 0, sizeof(id3v2Tag)); |
3179 | + get_id3v2tag_raw (v2, filename); |
3180 | + |
3181 | + oldsize = v2->tag_size; |
3182 | + |
3183 | +// If the old tag had an extheader, I'll add its size to my tag, because i don't plan to add it again. |
3184 | + if ( v2->has_extheader ) |
3185 | + { |
3186 | + v2->padding_size += v2->extheader_size; |
3187 | + v2->has_extheader = FALSE; |
3188 | + v2->extheader_size = 0; |
3189 | + } |
3190 | + |
3191 | +// first of all I'll generate a valid id3v2 tag struct out of the tag struct we got by the user. |
3192 | +// Set the flags... |
3193 | + v2->unsync = FALSE; |
3194 | + v2->is_experimental = FALSE; |
3195 | + v2->crc_data_present = FALSE; |
3196 | + |
3197 | +// Set the contentframes |
3198 | + frame_set (v2, "TIT2", tag->title); |
3199 | + frame_set (v2, "TPE1", tag->artist); |
3200 | + frame_set (v2, "TALB", tag->album); |
3201 | + frame_set (v2, "TYER", tag->year); |
3202 | + frame_set (v2, "COMM", tag->comment); |
3203 | + frame_set (v2, "TCON", tag->genre); |
3204 | + frame_set (v2, "TCOM", tag->composer); // Composer |
3205 | + frame_set (v2, "TOPE", tag->orig_artist); // TOPE Original artist(s)/performer(s) |
3206 | + frame_set (v2, "WCOM", tag->url); // URL |
3207 | + frame_set (v2, "TENC", tag->enc_by); // Encoded by |
3208 | + if ( atoi (tag->track) < 10 ) |
3209 | + snprintf (track, 3, "0%i", atoi(tag->track)); |
3210 | + else |
3211 | + snprintf (track, 3, "%i", atoi(tag->track)); |
3212 | + frame_set (v2, "TRCK", track); |
3213 | + |
3214 | +// Create a header in the raw data string |
3215 | + rawdata = calloc (1, v2->tag_size + 10); |
3216 | + create_header_raw (rawdata, v2); |
3217 | + |
3218 | +// Create frames raw data. |
3219 | + create_frames_raw (rawdata, v2); |
3220 | + |
3221 | +// is the new tag bigger than the old one? Then we'll have to completely rewrite the file... |
3222 | + if ( v2->tag_size > oldsize ) |
3223 | + { |
3224 | + FILE *file = NULL; |
3225 | + FILE *tempfile = NULL; |
3226 | + char *tempfilename = NULL; |
3227 | + int read = 0; |
3228 | + char buf[4096]; |
3229 | + |
3230 | +// Open a tempfile |
3231 | + error = 2; |
3232 | + tempfilename = malloc (strlen (filename) + 11); |
3233 | + sprintf (tempfilename, "%s%s", filename, ".tempXXXXX"); |
3234 | + if( !(tempfile = fopen(tempfilename, "wb")) ) |
3235 | + { |
3236 | + remove (tempfilename); |
3237 | + free (tempfilename); |
3238 | + goto done; |
3239 | + } |
3240 | + |
3241 | +// Write the tag to the tempfile. |
3242 | + error = 3; |
3243 | + fseek (tempfile, 0, SEEK_SET); |
3244 | + if( fwrite (rawdata, 1, v2->tag_size + 10, tempfile) < v2->tag_size ) |
3245 | + { |
3246 | + fclose (tempfile); |
3247 | + remove (tempfilename); |
3248 | + free (tempfilename); |
3249 | + goto done; |
3250 | + } |
3251 | + |
3252 | +// Open the mp3file. |
3253 | + error = 4; |
3254 | + if( !(file = fopen(filename, "r+b")) ) |
3255 | + { |
3256 | + fclose (file); |
3257 | + remove (tempfilename); |
3258 | + free (tempfilename); |
3259 | + goto done; |
3260 | + } |
3261 | +// skip the old tag (if one existed) |
3262 | + fseek (file, oldsize? oldsize + 10 : oldsize, SEEK_SET); |
3263 | + |
3264 | +// copy the rest of the file to the tempfile. |
3265 | + while ( !feof(file) ) |
3266 | + { |
3267 | + error = 5; |
3268 | + read = fread (buf, 1, 4096, file); |
3269 | + if( fwrite (buf, 1, read, tempfile) != read |
3270 | + && !feof (file) ) |
3271 | + { |
3272 | + remove (tempfilename); |
3273 | + free (tempfilename); |
3274 | + fflush (tempfile); |
3275 | + fclose (tempfile); |
3276 | + fflush (file); |
3277 | + fclose (file); |
3278 | + goto done; |
3279 | + } |
3280 | + } |
3281 | + |
3282 | + fflush (file); |
3283 | + fclose (file); |
3284 | + fflush (tempfile); |
3285 | + fclose (tempfile); |
3286 | + |
3287 | +// rename the tempfile, so it is the mp3file. |
3288 | + rename (tempfilename, filename); |
3289 | + free (tempfilename); |
3290 | + } |
3291 | + else |
3292 | + { |
3293 | + FILE *file = NULL; |
3294 | + |
3295 | +// If the old tag was bigger than the new one, we can simply overwrite it! |
3296 | +// open. |
3297 | + error = 10; |
3298 | + if( !(file = fopen(filename, "r+b")) ) |
3299 | + goto done; |
3300 | + |
3301 | +// write. |
3302 | + error = 11; |
3303 | + fseek (file, 0, SEEK_SET); |
3304 | + if( fwrite (rawdata, 1, v2->tag_size + 10, file) < v2->tag_size ) |
3305 | + { |
3306 | + fflush (file); |
3307 | + fclose (file); |
3308 | + goto done; |
3309 | + } |
3310 | + |
3311 | + fflush (file); |
3312 | + fclose (file); |
3313 | + } |
3314 | + |
3315 | + error = 0; |
3316 | + |
3317 | +done: |
3318 | +// Free all the stuff |
3319 | + curframe = v2->frames; |
3320 | + while ( curframe ) |
3321 | + { |
3322 | + frame = (id3v2Frame *)curframe->data; |
3323 | + |
3324 | + free (frame->data); |
3325 | + free (frame); |
3326 | + |
3327 | + curframe = curframe->next; |
3328 | + } |
3329 | + dll_free (v2->frames); |
3330 | + |
3331 | + if ( rawdata != NULL ) |
3332 | + free (rawdata); |
3333 | + free (v2); |
3334 | + return (error); |
3335 | +} |
3336 | diff -Naur xmms-1.2.9-orig/Input/mpg123/mpg123.c xmms-1.2.9/Input/mpg123/mpg123.c |
3337 | --- xmms-1.2.9-orig/Input/mpg123/mpg123.c Thu Jan 29 06:43:24 2004 |
3338 | +++ xmms-1.2.9/Input/mpg123/mpg123.c Thu Jan 29 05:18:54 2004 |
3339 | @@ -607,8 +607,13 @@ |
3340 | { \ |
3341 | id3frm = id3_get_frame( id3d, _tid, 1 ); \ |
3342 | if (id3frm) { \ |
3343 | - txt = _tid == ID3_TCON ? id3_get_content(id3frm) \ |
3344 | - : id3_get_text(id3frm); \ |
3345 | + if (_tid == ID3_COMM) \ |
3346 | + txt = id3_get_comm(id3frm); \ |
3347 | + else if (id3frm->fr_desc->fd_idstr[0] == 'W') \ |
3348 | + txt = id3_get_url(id3frm); \ |
3349 | + else \ |
3350 | + txt = _tid == ID3_TCON ? id3_get_content(id3frm) \ |
3351 | + : id3_get_text(id3frm); \ |
3352 | if(txt) \ |
3353 | { \ |
3354 | tlen = strlen(txt); \ |
3355 | @@ -644,6 +649,10 @@ |
3356 | ID3_SET_NUM (ID3_TRCK, track_number); |
3357 | ID3_SET (ID3_COMM, comment); |
3358 | ID3_SET (ID3_TCON, genre); |
3359 | + ID3_SET (ID3_TCOM, composer); |
3360 | + ID3_SET (ID3_TOPE, orig_artist); |
3361 | + ID3_SET (ID3_WCOM, url); |
3362 | + ID3_SET (ID3_TENC, encoded_by); |
3363 | } |
3364 | |
3365 | /* |
3366 | diff -Naur xmms-1.2.9-orig/Input/mpg123/mpg123.h xmms-1.2.9/Input/mpg123/mpg123.h |
3367 | --- xmms-1.2.9-orig/Input/mpg123/mpg123.h Thu Jan 29 06:43:24 2004 |
3368 | +++ xmms-1.2.9/Input/mpg123/mpg123.h Thu Jan 29 05:20:31 2004 |
3369 | @@ -78,6 +78,10 @@ |
3370 | char genre[256]; |
3371 | int year; |
3372 | int track_number; |
3373 | + char composer[1024]; |
3374 | + char orig_artist[1024]; |
3375 | + char url[1024]; |
3376 | + char encoded_by[1024]; |
3377 | }; |
3378 | |
3379 | typedef struct |