Magellan Linux

Contents of /trunk/xmms/patches/xmms-1.2.10-id3v2edit.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 153 - (show annotations) (download)
Tue May 8 20:52:56 2007 UTC (17 years 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