Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 153 - (hide annotations) (download)
Tue May 8 20:52:56 2007 UTC (17 years, 1 month ago) by niro
File size: 108172 byte(s)
-import

1 niro 153 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