diff options
author | Benjamin Drung <bdrung@ubuntu.com> | 2010-06-14 00:14:42 +0200 |
---|---|---|
committer | Benjamin Drung <bdrung@ubuntu.com> | 2010-06-14 00:14:42 +0200 |
commit | 42318926e1c1585ccc266c4607cb1d6e855bd0b9 (patch) | |
tree | 40144e79fc7ef2b106e7c23d77fb8a9ba0af5216 /src | |
parent | 56ad9eb46da6e9b941795b17fb4fa18b6f75c4ae (diff) |
Imported Upstream version 2.4~alpha1
Diffstat (limited to 'src')
162 files changed, 7665 insertions, 15187 deletions
diff --git a/src/Makefile b/src/Makefile index 249cb5b..a6d4f2c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,4 +1,4 @@ -SUBDIRS = libaudcore libguess libid3tag libaudtag audacious libaudgui tests +SUBDIRS = libaudcore libaudgui libguess libaudtag audacious include ../extra.mk diff --git a/src/audacious/Makefile b/src/audacious/Makefile index 680db2b..7b19c5c 100644 --- a/src/audacious/Makefile +++ b/src/audacious/Makefile @@ -3,16 +3,13 @@ include ../../extra.mk SUBDIRS = ${INTL_OBJECTIVE} PROG = audacious2${PROG_SUFFIX} -SRCS = af_equalizer.c \ - auddrct.c \ +SRCS = auddrct.c \ audconfig.c \ - build_stamp.c \ chardet.c \ configdb.c \ credits.c \ effect.c \ equalizer.c \ - equalizer_flow.c \ equalizer_preset.c \ eventqueue.c \ fft.c \ @@ -34,16 +31,13 @@ SRCS = af_equalizer.c \ probe.c \ rcfile.c \ signals.c \ - ui_fileinfopopup.c \ ui_headless.c \ ui_plugin_menu.c \ ui_preferences.c \ util.c \ vis_runner.c \ visualization.c \ - sync-menu.c \ ui_albumart.c \ - ui_fileinfo.c \ ui_misc.c ifeq ($(USE_DBUS),yes) @@ -64,15 +58,11 @@ INCLUDES = auddrct.h \ hook.h \ interface.h \ main.h \ - output.h \ playback.h \ playlist_container.h \ plugin.h \ preferences.h \ - ui_fileinfopopup.h \ - ui_plugin_menu.h \ - ui_preferences.h \ - util.h + ui_plugin_menu.h DATA = images/about-logo.png \ images/appearance.png \ @@ -96,7 +86,7 @@ DATA = images/about-logo.png \ ui/playlist.ui \ ui/carbon-menubar.ui -CLEAN = build_stamp.c libaudacious.exe.a +CLEAN = build_stamp.c dbus-client-bindings.h dbus-server-bindings.h EXT_DEPS = ../libguess/libguess.a ifeq ($(USE_EGGSM),yes) @@ -131,10 +121,13 @@ CPPFLAGS += -DHAVE_CONFIG_H \ -I.. -I../.. \ -I./intl \ -I. \ - -I../libaudcore + -I../libaudcore \ + -I../libaudtag LIBS += ${LDADD} \ -L../libaudcore -laudcore \ + -L../libaudgui -laudgui \ + -L../libaudtag -laudtag \ ${LIBINTL} \ ../libguess/libguess.a \ ${EGGSM_LIBS} \ @@ -151,7 +144,7 @@ LDFLAGS += ${PROG_IMPLIB_LDFLAGS} ${AUDLDFLAGS} build_stamp.c: echo "#include <glib.h>" > build_stamp.c ; \ if test -d ../../.hg ; then \ - revh=`hg tip --template 'const gchar *build_stamp = "#rev#:#node|short#";\n' 2>/dev/null`; \ + revh=`hg tip --template 'const gchar *build_stamp = "{rev}:{node|short}";\n' 2>/dev/null`; \ [ -z "$$revh" ] || echo "$$revh" >> build_stamp.c; \ else \ echo "const gchar *build_stamp = \"UNSUPPORTED VERSION\";" >> build_stamp.c; \ @@ -176,7 +169,7 @@ dbus-client-bindings.h: ${DBUS_BINDINGS_SOURCES} install-extra: if test -h "${DESTDIR}${bindir}/audacious" ; then ${RM} "${DESTDIR}${bindir}/audacious" ; fi - ${LN_S} "${DESTDIR}${bindir}/audacious2" "${DESTDIR}${bindir}/audacious" + ${LN_S} audacious2 "${DESTDIR}${bindir}/audacious" if test x"${PROG_IMPLIB_NEEDED}" = x"yes"; then \ for i in ${PROG}; do \ diff --git a/src/audacious/af_compat.h b/src/audacious/af_compat.h deleted file mode 100644 index e8f1fb6..0000000 --- a/src/audacious/af_compat.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * MPlayer libaf compatibility stuff - */ - -#ifndef AUDACIOUS_AF_COMPAT_H -#define AUDACIOUS_AF_COMPAT_H - -#include <glib.h> -#include "main.h" - -/* Number of channels */ -#ifndef AF_NCH -#define AF_NCH 6 -#endif - -/* Format */ -#define AF_FORMAT_BE (0<<0) // Big Endian -#define AF_FORMAT_LE (1<<0) // Little Endian -#define AF_FORMAT_F (1<<2) // Foating point -#define AF_FORMAT_32BIT (3<<3) -#define AF_FORMAT_FLOAT_LE (AF_FORMAT_F|AF_FORMAT_32BIT|AF_FORMAT_LE) -#define AF_FORMAT_FLOAT_BE (AF_FORMAT_F|AF_FORMAT_32BIT|AF_FORMAT_BE) - -#if G_BYTE_ORDER == G_BIG_ENDIAN // Native endian of cpu -#define AF_FORMAT_FLOAT_NE AF_FORMAT_FLOAT_BE -#else -#define AF_FORMAT_FLOAT_NE AF_FORMAT_FLOAT_LE -#endif - -#define AF_MSG_INFO 0 ///< Important information - -#define af_msg(a,...) AUDDBG(__VA_ARGS__); - -/* Control */ -#define AF_CONTROL_SET 0x00000000 -#define AF_CONTROL_GET 0x00000001 - -#define AF_CONTROL_MANDATORY 0x10000000 -#define AF_CONTROL_OPTIONAL 0x20000000 -#define AF_CONTROL_FILTER_SPECIFIC 0x40000000 - -#define AF_CONTROL_REINIT 0x00000100 | AF_CONTROL_MANDATORY -#define AF_CONTROL_EQUALIZER_GAIN 0x00001C00 | AF_CONTROL_FILTER_SPECIFIC - -/* Return values */ -#define AF_DETACH 2 -#define AF_OK 1 -#define AF_TRUE 1 -#define AF_FALSE 0 -#define AF_UNKNOWN -1 -#define AF_ERROR -2 -#define AF_FATAL -3 - -/* Audio data chunk */ -typedef struct af_data_s -{ - void* audio; /* data buffer */ - int len; /* buffer length */ - int rate; /* sample rate */ - int nch; /* number of channels */ - int format; /* format */ - int bps; /* bytes per sample */ -} af_data_t; - -struct af_instance_s; -/* Audio filter information not specific for current instance, but for - a specific filter */ -typedef struct af_info_s -{ - const char *info; - const char *name; - const char *author; - const char *comment; - const int flags; - int (*open)(struct af_instance_s* vf); -} af_info_t; - -/* Linked list of audio filters */ -typedef struct af_instance_s -{ - af_info_t* info; - int (*control)(struct af_instance_s* af, int cmd, void* arg); - void (*uninit)(struct af_instance_s* af); - af_data_t* (*play)(struct af_instance_s* af, af_data_t* data); - void* setup; // setup data for this specific instance and filter - af_data_t* data; // configuration for outgoing data stream - struct af_instance_s* next; - struct af_instance_s* prev; - double delay; /* Delay caused by the filter, in units of bytes read without - * corresponding output */ - double mul; /* length multiplier: how much does this instance change - the length of the buffer. */ -}af_instance_t; - -/********************************************* - Extended control used with arguments that operates on only one - channel at the time -*/ -typedef struct af_control_ext_s{ - void* arg; // Argument - int ch; // Chanel number -}af_control_ext_t; - -#endif /* AUDACIOUS_AF_COMPAT_H */ diff --git a/src/audacious/af_equalizer.c b/src/audacious/af_equalizer.c deleted file mode 100644 index 71c78bf..0000000 --- a/src/audacious/af_equalizer.c +++ /dev/null @@ -1,196 +0,0 @@ -/*============================================================================= -// -// This software has been released under the terms of the GNU General Public -// license. See http://www.gnu.org/copyleft/gpl.html for details. -// -// Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au -// -//============================================================================= -*/ - -/* Equalizer filter, implementation of a 10 band time domain graphic - equalizer using IIR filters. The IIR filters are implemented using a - Direct Form II approach, but has been modified (b1 == 0 always) to - save computation. -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <inttypes.h> -#include <math.h> - -#include "af_compat.h" - -#define L 2 // Storage for filter taps -#define KM 10 // Max number of bands - -#define Q 1.2247449 -/* Q value for band-pass filters 1.2247=(3/2)^(1/2) - gives 4dB suppression @ Fc*2 and Fc/2 */ - -/* Center frequencies for band-pass filters - The different frequency bands are: - nr. center frequency - 0 31.25 Hz - 1 62.50 Hz - 2 125.0 Hz - 3 250.0 Hz - 4 500.0 Hz - 5 1.000 kHz - 6 2.000 kHz - 7 4.000 kHz - 8 8.000 kHz - 9 16.00 kHz -*/ -/*#define CF {31.25,62.5,125,250,500,1000,2000,4000,8000,16000}*/ -#define CF {60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000} - -// Data for specific instances of this filter -typedef struct af_equalizer_s -{ - float a[KM][L]; // A weights - float b[KM][L]; // B weights - float wq[AF_NCH][KM][L]; // Circular buffer for W data - float g[AF_NCH][KM]; // Gain factor for each channel and band - int K; // Number of used eq bands - int channels; // Number of channels -} af_equalizer_t; - -static int af_test_output(struct af_instance_s* af, af_data_t* out) -{ - if((af->data->format != out->format) || - (af->data->bps != out->bps) || - (af->data->rate != out->rate) || - (af->data->nch != out->nch)){ - memcpy(out,af->data,sizeof(af_data_t)); - return AF_FALSE; - } - return AF_OK; -} - -// 2nd order Band-pass Filter design -static void bp2(float* a, float* b, float fc, float q){ - double th= 2.0 * M_PI * fc; - double C = (1.0 - tan(th*q/2.0))/(1.0 + tan(th*q/2.0)); - - a[0] = (1.0 + C) * cos(th); - a[1] = -1 * C; - - b[0] = (1.0 - C)/2.0; - b[1] = -1.0050; -} - -// Initialization and runtime control -static int control(struct af_instance_s* af, int cmd, void* arg) -{ - af_equalizer_t* s = (af_equalizer_t*)af->setup; - - switch(cmd){ - case AF_CONTROL_REINIT:{ - int k = 0; - float F[KM] = CF; - - // Sanity check - if(!arg) return AF_ERROR; - - af->data->rate = ((af_data_t*)arg)->rate; - af->data->nch = ((af_data_t*)arg)->nch; - af->data->format = AF_FORMAT_FLOAT_NE; - af->data->bps = 4; - - // Calculate number of active filters - s->K=KM; - while(F[s->K-1] > (float)af->data->rate/2.2) - s->K--; - - if(s->K != KM) - af_msg(AF_MSG_INFO,"[equalizer] Limiting the number of filters to" - " %i due to low sample rate.\n",s->K); - - // Generate filter taps - for(k=0;k<s->K;k++) - bp2(s->a[k],s->b[k],F[k]/((float)af->data->rate),Q); - - // Calculate how much this plugin adds to the overall time delay - af->delay = 2 * af->data->nch * af->data->bps; - - return af_test_output(af,arg); - } - case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_SET:{ - float* gain = ((af_control_ext_t*)arg)->arg; - int ch = ((af_control_ext_t*)arg)->ch; - int k; - if(ch >= AF_NCH || ch < 0) - return AF_ERROR; - - for(k = 0 ; k<KM ; k++) - s->g[ch][k] = pow (10, gain[k] / 20) - 1; - - return AF_OK; - } - } - return AF_UNKNOWN; -} - -// Deallocate memory -static void uninit(struct af_instance_s* af) -{ - if(af->data) - free(af->data); - if(af->setup) - free(af->setup); -} - -// Filter data through filter -static af_data_t* play(struct af_instance_s* af, af_data_t* data) -{ - af_data_t* c = data; // Current working data - af_equalizer_t* s = (af_equalizer_t*)af->setup; // Setup - uint32_t ci = af->data->nch; // Index for channels - uint32_t nch = af->data->nch; // Number of channels - - while(ci--){ - float* g = s->g[ci]; // Gain factor - float* in = ((float*)c->audio)+ci; - float* out = ((float*)c->audio)+ci; - float* end = in + c->len/4; // Block loop end - - while(in < end){ - register int k = 0; // Frequency band index - register float yt = *in; // Current input sample - in+=nch; - - // Run the filters - for(;k<s->K;k++){ - // Pointer to circular buffer wq - register float* wq = s->wq[ci][k]; - // Calculate output from AR part of current filter - register float w=yt*s->b[k][0] + wq[0]*s->a[k][0] + wq[1]*s->a[k][1]; - // Calculate output form MA part of current filter - yt+=(w + wq[1]*s->b[k][1])*g[k]; - // Update circular buffer - wq[1] = wq[0]; - wq[0] = w; - } - // Calculate output - * out = yt; - out+=nch; - } - } - return c; -} - -// Allocate memory and set function pointers -int equalizer_open(af_instance_t* af){ - af->control=control; - af->uninit=uninit; - af->play=play; - af->mul=1; - af->data=calloc(1,sizeof(af_data_t)); - af->setup=calloc(1,sizeof(af_equalizer_t)); - if(af->data == NULL || af->setup == NULL) - return AF_ERROR; - return AF_OK; -} diff --git a/src/audacious/audconfig.c b/src/audacious/audconfig.c index 9743374..47c376a 100644 --- a/src/audacious/audconfig.c +++ b/src/audacious/audconfig.c @@ -1,5 +1,5 @@ /* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2008 Audacious development team. + * Copyright (C) 2005-2010 Audacious development team. * * Based on BMP: * Copyright (C) 2003-2004 BMP development team. @@ -31,9 +31,8 @@ #include "effect.h" #include "general.h" +#include "output.h" #include "playback.h" -#include "playlist-new.h" -#include "playlist-utils.h" #include "pluginenum.h" #include "plugin-registry.h" #include "util.h" @@ -91,9 +90,17 @@ AudConfig aud_default_config = { .replay_gain_preamp = 0, .default_gain = 0, .sw_volume_left = 100, .sw_volume_right = 100, - .clear_playlist = FALSE, + .clear_playlist = TRUE, .output_path = NULL, .output_number = -1, + + /* libaudgui stuff */ + .no_confirm_playlist_delete = FALSE, + .playlist_manager_x = 0, + .playlist_manager_y = 0, + .playlist_manager_width = 0, + .playlist_manager_height = 0, + .playlist_manager_close_on_activate = FALSE, }; typedef struct aud_cfg_boolent_t { @@ -138,7 +145,10 @@ static aud_cfg_boolent aud_boolents[] = { {"enable_clipping_prevention", &cfg.enable_clipping_prevention, TRUE}, {"replay_gain_track", &cfg.replay_gain_track, TRUE}, {"replay_gain_album", &cfg.replay_gain_album, TRUE}, - {"clear_playlist", & cfg.clear_playlist, TRUE}, + {"clear_playlist", &cfg.clear_playlist, TRUE}, + {"no_confirm_playlist_delete", &cfg.no_confirm_playlist_delete, TRUE}, + {"playlist_manager_close_on_activate", + & cfg.playlist_manager_close_on_activate, TRUE}, }; static gint ncfgbent = G_N_ELEMENTS(aud_boolents); @@ -155,6 +165,10 @@ static aud_cfg_nument aud_numents[] = { {"sw_volume_left", & cfg.sw_volume_left, TRUE}, {"sw_volume_right", & cfg.sw_volume_right, TRUE}, {"output_number", & cfg.output_number, TRUE}, + {"playlist_manager_x", & cfg.playlist_manager_x, TRUE}, + {"playlist_manager_y", & cfg.playlist_manager_y, TRUE}, + {"playlist_manager_width", & cfg.playlist_manager_width, TRUE}, + {"playlist_manager_height", & cfg.playlist_manager_height, TRUE}, }; static gint ncfgient = G_N_ELEMENTS(aud_numents); @@ -177,134 +191,6 @@ static aud_cfg_strent aud_strents[] = { static gint ncfgsent = G_N_ELEMENTS(aud_strents); - -static gboolean -save_extra_playlist(const gchar * path, const gchar * basename, - gpointer savedlist) -{ - gint playlists, playlist; - GList **saved; - int found; - const gchar * filename; - - playlists = playlist_count (); - saved = (GList **) savedlist; - - found = 0; - - for (playlist = 0; playlist < playlists; playlist ++) - { - if (g_list_find (* saved, GINT_TO_POINTER (playlist)) != NULL) - continue; - - filename = playlist_get_filename (playlist); - - if (filename == NULL) - continue; - - if (strcmp(filename, path) == 0) { - /* Save playlist */ - playlist_save(playlist, path); - * saved = g_list_prepend (* saved, GINT_TO_POINTER (playlist)); - found = 1; - break; - } - } - - if(!found) { - /* Remove playlist */ - unlink(path); - } - - return FALSE; /* process other playlists */ -} - -static void -save_other_playlists(GList *saved) -{ - gint playlists, playlist; - gchar * pos, * ext, * basename, * newbasename, * new_filename; - const gchar * filename; - int i, num, isdigits; - - playlists = playlist_count (); - - for (playlist = 0; playlist < playlists; playlist ++) - { - if (g_list_find (saved, GINT_TO_POINTER (playlist)) != NULL) - continue; - - filename = playlist_get_filename (playlist); - - if (filename == NULL || g_file_test (filename, G_FILE_TEST_IS_DIR)) - { - /* default basename */ -#ifdef HAVE_XSPF_PLAYLIST - basename = g_strdup("playlist_01.xspf"); -#else - basename = g_strdup("playlist_01.m3u"); -#endif - } else { - basename = g_path_get_basename(filename); - } - - if ((pos = strrchr(basename, '.'))) { - *pos = '\0'; - } -#ifdef HAVE_XSPF_PLAYLIST - ext = ".xspf"; -#else - ext = ".m3u"; -#endif - num = -1; - if ((pos = strrchr(basename, '_'))) { - isdigits = 0; - for (i=1; pos[i]; i++) { - if (!g_ascii_isdigit(pos[i])) { - isdigits = 0; - break; - } - isdigits = 1; - } - if (isdigits) { - num = atoi(pos+1) + 1; - *pos = '\0'; - } - } - /* attempt to generate unique filename */ - new_filename = NULL; - - do { - g_free (new_filename); - - if (num < 0) { - /* try saving without number first */ - newbasename = g_strdup_printf("%s%s", basename, ext); - num = 1; - } else { - newbasename = g_strdup_printf("%s_%02d%s", basename, num, ext); - num++; - if (num < 0) { - g_warning("Playlist number in filename overflowed." - " Not saving playlist.\n"); - goto cleanup; - } - } - - new_filename = g_build_filename (aud_paths[BMP_PATH_PLAYLISTS_DIR], - newbasename, NULL); - g_free(newbasename); - } - while (g_file_test (new_filename, G_FILE_TEST_EXISTS)); - - playlist_save (playlist, new_filename); -cleanup: - g_free (new_filename); - g_free(basename); - } -} - - void aud_config_free(void) { @@ -397,26 +283,6 @@ aud_config_load(void) cfg.cover_name_exclude = g_strdup("back"); } -void save_all_playlists (void) -{ - GList * saved; - - /* Main playlist becomes #0 at load, so save #0 as main. -jlindgren */ - if (! playlist_save (0, aud_paths[BMP_PATH_PLAYLIST_FILE])) - g_warning ("Could not save main playlist\n"); - - /* Save extra playlists that were loaded from PLAYLISTS_DIR */ - saved = g_list_append (NULL, GINT_TO_POINTER (0)); - - if (! dir_foreach (aud_paths[BMP_PATH_PLAYLISTS_DIR], save_extra_playlist, - & saved, NULL)) - g_warning ("Could not save extra playlists\n"); - - /* Save other playlists to PLAYLISTS_DIR */ - save_other_playlists (saved); - g_list_free (saved); -} - static void save_output_path (void) { const gchar * path = NULL; @@ -437,6 +303,8 @@ aud_config_save(void) gint i; mcs_handle_t *db; + hook_call ("config save", NULL); + cfg.resume_state = playback_get_playing () ? (playback_get_paused () ? 2 : 1) : 0; cfg.resume_playback_on_startup_time = playback_get_playing () ? @@ -458,8 +326,6 @@ aud_config_save(void) aud_numents[i].ie_vname, *aud_numents[i].ie_vloc); - hook_call("config save", db); - for (i = 0; i < ncfgsent; ++i) { if (aud_strents[i].se_wrt) cfg_db_set_string(db, NULL, @@ -519,6 +385,4 @@ aud_config_save(void) } cfg_db_close(db); - - save_all_playlists (); } diff --git a/src/audacious/audconfig.h b/src/audacious/audconfig.h index d739769..6350974 100644 --- a/src/audacious/audconfig.h +++ b/src/audacious/audconfig.h @@ -1,5 +1,5 @@ /* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2008 Audacious development team + * Copyright (C) 2005-2010 Audacious development team * * Based on BMP: * Copyright (C) 2003-2004 BMP development team @@ -76,6 +76,12 @@ struct _AudConfig { gboolean clear_playlist; gchar * output_path; gint output_number; + + /* libaudgui stuff */ + gboolean no_confirm_playlist_delete; + gint playlist_manager_x, playlist_manager_y, playlist_manager_width, + playlist_manager_height; + gboolean playlist_manager_close_on_activate; }; typedef struct _AudConfig AudConfig; @@ -83,8 +89,6 @@ typedef struct _AudConfig AudConfig; extern AudConfig cfg; extern AudConfig aud_default_config; -void save_all_playlists (void); - void aud_config_free(void); void aud_config_load(void); void aud_config_save(void); diff --git a/src/audacious/build_stamp.h b/src/audacious/build_stamp.h deleted file mode 100644 index 9aa3ca3..0000000 --- a/src/audacious/build_stamp.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef AUDACIOUS_BUILD_STAMP_H -#define AUDACIOUS_BUILD_STAMP_H - -extern const char *build_stamp; - -#endif /* AUDACIOUS_BUILD_STAMP_H */ diff --git a/src/audacious/credits.c b/src/audacious/credits.c index 52701ab..7f6b135 100644 --- a/src/audacious/credits.c +++ b/src/audacious/credits.c @@ -70,6 +70,7 @@ static const gchar *credit_text[] = { "Matti Hämäläinen", "Sascha Hlusiak", "John Lindgren", + "Michał Lipski", "Giacomo Lozito", "Cristi Măgherușan", "Boris Mikhaylov", @@ -99,7 +100,6 @@ static const gchar *credit_text[] = { "Jussi Judin", "Teru KAMOGASHIRA", "Chris Kehler", - "Michał Lipski", "Mark Loeser", "Alex Maclean", "Michael Hanselmann", diff --git a/src/audacious/dbus.c b/src/audacious/dbus.c index 87ecbf2..c75d7a6 100644 --- a/src/audacious/dbus.c +++ b/src/audacious/dbus.c @@ -1,7 +1,7 @@ /* * Audacious: A cross-platform multimedia player * Copyright (c) 2007 Ben Tucker - * Copyright 2009 John Lindgren + * Copyright 2009-2010 Audacious development team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -263,7 +263,7 @@ static void tuple_insert_to_hash_full(GHashTable * md, const Tuple * tuple, { GValue *value = tuple_value_to_gvalue(tuple, tuple_key); if (value != NULL) - g_hash_table_insert(md, g_strdup(key), value); + g_hash_table_insert (md, (void *) key, value); } static void tuple_insert_to_hash(GHashTable * md, const Tuple * tuple, @@ -644,7 +644,6 @@ static void get_mpris_metadata(struct MprisMetadataRequest *request) static gboolean set_shuffle_cb (void * shuffle) { cfg.shuffle = GPOINTER_TO_INT (shuffle); - playlist_set_shuffle (cfg.shuffle); event_queue ("toggle shuffle", NULL); return FALSE; } @@ -1412,61 +1411,58 @@ gboolean audacious_rc_get_eq(RemoteObject * obj, gdouble * preamp, GArray ** ban { int i; - *preamp = (gdouble) equalizer_get_preamp(); + * preamp = cfg.equalizer_preamp; *bands = g_array_sized_new(FALSE, FALSE, sizeof(gdouble), AUD_EQUALIZER_NBANDS); for (i = 0; i < AUD_EQUALIZER_NBANDS; i++) - { - gdouble val = (gdouble) equalizer_get_band(i); - g_array_append_val(*bands, val); - } + g_array_append_val (* bands, cfg.equalizer_bands[i]); return TRUE; } gboolean audacious_rc_get_eq_preamp(RemoteObject * obj, gdouble * preamp, GError ** error) { - *preamp = (gdouble) equalizer_get_preamp(); + * preamp = cfg.equalizer_preamp; return TRUE; } gboolean audacious_rc_get_eq_band(RemoteObject * obj, gint band, gdouble * value, GError ** error) { - *value = (gdouble) equalizer_get_band(band); + * value = cfg.equalizer_bands[band]; return TRUE; } gboolean audacious_rc_set_eq(RemoteObject * obj, gdouble preamp, GArray * bands, GError ** error) { - gdouble element; int i; - equalizer_set_preamp((gfloat) preamp); + cfg.equalizer_preamp = preamp; for (i = 0; i < AUD_EQUALIZER_NBANDS; i++) - { - element = g_array_index(bands, gdouble, i); - equalizer_set_band(i, (gfloat) element); - } + cfg.equalizer_bands[i] = g_array_index (bands, gdouble, i); + hook_call ("equalizer changed", NULL); return TRUE; } gboolean audacious_rc_set_eq_preamp(RemoteObject * obj, gdouble preamp, GError ** error) { - equalizer_set_preamp((gfloat) preamp); + cfg.equalizer_preamp = preamp; + hook_call ("equalizer changed", NULL); return TRUE; } gboolean audacious_rc_set_eq_band(RemoteObject * obj, gint band, gdouble value, GError ** error) { - equalizer_set_band(band, (gfloat) value); + cfg.equalizer_bands[band] = value; + hook_call ("equalizer changed", NULL); return TRUE; } gboolean audacious_rc_equalizer_activate(RemoteObject * obj, gboolean active, GError ** error) { - equalizer_set_active(active); + cfg.equalizer_active = active; + hook_call ("equalizer changed", NULL); return TRUE; } diff --git a/src/audacious/effect.c b/src/audacious/effect.c index 2f15d68..03ad53f 100644 --- a/src/audacious/effect.c +++ b/src/audacious/effect.c @@ -199,21 +199,27 @@ static GList * new_effect_list = NULL; void new_effect_start (gint * channels, gint * rate) { + gint order; GList * node; EffectPlugin * effect; g_list_free (new_effect_list); new_effect_list = NULL; - /* FIXME: Let the user define in what order the effects are applied. */ - for (node = ep_data.enabled_list; node != NULL; node = node->next) + for (order = 0; order < 10; order ++) { - effect = node->data; + for (node = ep_data.enabled_list; node != NULL; node = node->next) + { + effect = node->data; + + if (effect->order != order) + continue; - if (effect->start != NULL) - new_effect_list = g_list_prepend (new_effect_list, effect); - else - printf ("Please update %s to new API.\n", effect->description); + if (effect->start != NULL) + new_effect_list = g_list_prepend (new_effect_list, effect); + else + printf ("Please update %s to new API.\n", effect->description); + } } new_effect_list = g_list_reverse (new_effect_list); diff --git a/src/audacious/effect.h b/src/audacious/effect.h index c8a6408..cc95c24 100644 --- a/src/audacious/effect.h +++ b/src/audacious/effect.h @@ -28,8 +28,7 @@ #include <glib.h> -#include "audacious/flow.h" -#include "audacious/output.h" +#include "audacious/plugin.h" typedef struct _EffectPluginData EffectPluginData; diff --git a/src/audacious/equalizer.c b/src/audacious/equalizer.c index cfd002c..6503762 100644 --- a/src/audacious/equalizer.c +++ b/src/audacious/equalizer.c @@ -1,77 +1,159 @@ -/* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2008 Audacious development team. +/* + * Equalizer filter, implementation of a 10 band time domain graphic equalizer + * using IIR filters. The IIR filters are implemented using a Direct Form II + * approach, modified (b1 == 0 always) to save computation. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. + * This software has been released under the terms of the GNU General Public + * license. See http://www.gnu.org/copyleft/gpl.html for details. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright 2001 Anders Johansson <ajh@atri.curtin.edu.au> * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses>. - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. + * Adapted for Audacious by John Lindgren, 2010 */ -#ifdef _AUDACIOUS_CORE -# include "config.h" -#endif +#include <glib.h> +#include <math.h> +#include <string.h> +#include "audconfig.h" #include "equalizer.h" -#include "equalizer_flow.h" #include "hook.h" -#include "output.h" -#include "audconfig.h" -static void eq_update (void * hook_data, void * user_data) -{ - equalizer_flow_set_bands (cfg.equalizer_preamp, cfg.equalizer_bands); -} +#define EQ_BANDS AUD_EQUALIZER_NBANDS +#define MAX_CHANNELS 10 -void init_equalizer (void) +/* Q value for band-pass filters 1.2247 = (3/2)^(1/2) + * Gives 4 dB suppression at Fc*2 and Fc/2 */ +#define Q 1.2247449 + +/* Center frequencies for band-pass filters (Hz) */ +static const gfloat CF[EQ_BANDS] = {60, 170, 310, 600, 1000, 3000, 6000, 12000, + 14000, 16000}; + +static GStaticMutex mutex = G_STATIC_MUTEX_INIT; +static gboolean active; +static gint channels, rate; +static gfloat a[EQ_BANDS][2]; /* A weights */ +static gfloat b[EQ_BANDS][2]; /* B weights */ +static gfloat wqv[MAX_CHANNELS][EQ_BANDS][2]; /* Circular buffer for W data */ +static gfloat gv[MAX_CHANNELS][EQ_BANDS]; /* Gain factor for each channel and band */ +static gint K; /* Number of used eq bands */ + +/* 2nd order band-pass filter design */ +static void bp2 (gfloat * a, gfloat * b, gfloat fc, gfloat q) { - hook_associate ("equalizer changed", eq_update, NULL); - eq_update (NULL, NULL); + gfloat th = 2 * M_PI * fc; + gfloat C = (1 - tanf (th * q / 2)) / (1 + tanf (th * q / 2)); + + a[0] = (1 + C) * cosf (th); + a[1] = -C; + b[0] = (1 - C) / 2; + b[1] = -1.005; } -gfloat -equalizer_get_preamp(void) +void eq_set_format (gint new_channels, gint new_rate) { - return cfg.equalizer_preamp; + gint k; + + g_static_mutex_lock (& mutex); + + channels = new_channels; + rate = new_rate; + + /* Calculate number of active filters */ + K = EQ_BANDS; + + while (CF[K - 1] > (gfloat) rate / 2.2) + K --; + + /* Generate filter taps */ + for (k = 0; k < K; k ++) + bp2 (a[k], b[k], CF[k] / (gfloat) rate, Q); + + /* Reset state */ + memset (wqv[0][0], 0, sizeof wqv); + + g_static_mutex_unlock (& mutex); } -void -equalizer_set_preamp(gfloat preamp) +static void eq_set_channel_bands (gint channel, gfloat * bands) { - cfg.equalizer_preamp = preamp; - eq_update (NULL, NULL); + gint k; + + for (k = 0; k < EQ_BANDS; k ++) + gv[channel][k] = pow (10, bands[k] / 20) - 1; } -gfloat -equalizer_get_band(gint band) +static void eq_set_bands (gfloat preamp, gfloat * bands) { - return cfg.equalizer_bands[band]; + gfloat adjusted[EQ_BANDS]; + gint i; + + for (i = 0; i < EQ_BANDS; i ++) + adjusted[i] = preamp + bands[i]; + + for (i = 0; i < MAX_CHANNELS; i ++) + eq_set_channel_bands (i, adjusted); } -void -equalizer_set_band(gint band, gfloat value) +void eq_filter (gfloat * data, gint samples) { - cfg.equalizer_bands[band] = value; - eq_update (NULL, NULL); + gint channel; + + g_static_mutex_lock (& mutex); + + if (! active) + { + g_static_mutex_unlock (& mutex); + return; + } + + for (channel = 0; channel < channels; channel ++) + { + gfloat * g = gv[channel]; /* Gain factor */ + gfloat * end = data + samples; + gfloat * f; + + for (f = data + channel; f < end; f += channels) + { + gint k; /* Frequency band index */ + gfloat yt = * f; /* Current input sample */ + + for (k = 0; k < K; k ++) + { + /* Pointer to circular buffer wq */ + gfloat * wq = wqv[channel][k]; + /* Calculate output from AR part of current filter */ + gfloat w = yt * b[k][0] + wq[0] * a[k][0] + wq[1] * a[k][1]; + + /* Calculate output from MA part of current filter */ + yt += (w + wq[1] * b[k][1]) * g[k]; + + /* Update circular buffer */ + wq[1] = wq[0]; + wq[0] = w; + } + + /* Calculate output */ + * f = yt; + } + } + + g_static_mutex_unlock (& mutex); } -gboolean equalizer_get_active(gboolean active) +static void eq_update (void * data, void * user_data) { - return cfg.equalizer_active; + g_static_mutex_lock (& mutex); + + active = cfg.equalizer_active; + eq_set_bands (cfg.equalizer_preamp, cfg.equalizer_bands); + + g_static_mutex_unlock (& mutex); } -void -equalizer_set_active(gboolean active) +void eq_init (void) { - cfg.equalizer_active = active; eq_update (NULL, NULL); + hook_associate ("equalizer changed", eq_update, NULL); } diff --git a/src/audacious/equalizer.h b/src/audacious/equalizer.h index aba93d9..68ec61f 100644 --- a/src/audacious/equalizer.h +++ b/src/audacious/equalizer.h @@ -1,35 +1,29 @@ -/* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2008 Audacious development team. +/* + * equalizer.h + * Copyright 2010 John Lindgren * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. + * This file is part of Audacious. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 or version 3 of the License. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses>. + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. */ #ifndef AUDACIOUS_EQUALIZER_H #define AUDACIOUS_EQUALIZER_H -#include <glib.h> - -void init_equalizer (void); - -gfloat equalizer_get_preamp(void); -void equalizer_set_preamp(gfloat preamp); -gfloat equalizer_get_band(gint band); -void equalizer_set_band(gint band, gfloat value); - -gboolean equalizer_get_active(); -void equalizer_set_active(gboolean active); +void eq_init (void); +void eq_set_format (gint new_channels, gint new_rate); +void eq_filter (gfloat * data, gint samples); #endif diff --git a/src/audacious/equalizer_flow.c b/src/audacious/equalizer_flow.c deleted file mode 100644 index f5c6395..0000000 --- a/src/audacious/equalizer_flow.c +++ /dev/null @@ -1,113 +0,0 @@ -/* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2008 Audacious team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses>. - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#include <glib.h> -#include <math.h> -#include "main.h" -#include "plugin.h" -#include "flow.h" - -#include "af_compat.h" -#include "equalizer_flow.h" - -int equalizer_open(af_instance_t* af); /* af_equalizer.c */ - -static af_instance_t *eq = NULL; -static gint eq_nch = 0; -static gint eq_rate = 0; -static gboolean bands_changed = FALSE; - -static void -equalizer_flow_reinit(gint rate, gint nch) -{ - af_data_t data; - - if(eq == NULL) return; - - data.rate = rate; - data.nch = nch; - data.bps = 4; - data.format = AF_FORMAT_FLOAT_NE; - eq->control(eq, AF_CONTROL_REINIT, &data); -} - -void -equalizer_flow(FlowContext *context) -{ - af_data_t data; - - if(!cfg.equalizer_active || eq == NULL) return; - - if(context->fmt != FMT_FLOAT) { - context->error = TRUE; - return; - } - - if(eq_nch != context->channels || - eq_rate != context->srate || - bands_changed) { - equalizer_flow_reinit(context->srate, context->channels); - eq_nch = context->channels; - eq_rate = context->srate; - bands_changed = FALSE; - } - - data.nch = context->channels; - data.audio = context->data; - data.len = context->len; - eq->play(eq, &data); -} - -void -equalizer_flow_set_bands(gfloat pre, gfloat *bands) -{ - int i; - af_control_ext_t ctl; - float adjusted [10]; /* ctl.arg is (float *), not (gfloat *) */ - - if(eq == NULL) { - eq = g_malloc(sizeof(af_instance_t)); - equalizer_open(eq); - } - - for (i = 0; i < 10; i ++) - adjusted[i] = (bands[i] + pre); - - ctl.arg = adjusted; - for (i = 0; i < AF_NCH; i++) { - ctl.ch = i; - eq->control(eq, AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_SET, &ctl); - } - - bands_changed = TRUE; -} - -void -equalizer_flow_free() -{ - AUDDBG("\n"); - if(eq != NULL) { - eq->uninit(eq); - g_free(eq); - eq = NULL; - eq_nch = 0; - eq_rate = 0; - bands_changed = FALSE; - } -} diff --git a/src/audacious/equalizer_flow.h b/src/audacious/equalizer_flow.h deleted file mode 100644 index 9b298f0..0000000 --- a/src/audacious/equalizer_flow.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef AUDACIOUS_EQUALIZER_FLOW_H -#define AUDACIOUS_EQUALIZER_FLOW_H - -#include "flow.h" - -#define EQUALIZER_MAX_GAIN 12.0 - -void equalizer_flow(FlowContext *context); -void equalizer_flow_set_bands(gfloat pre, gfloat *bands); -void equalizer_flow_free(); - -#endif /* AUDACIOUS_EQUALIZER_FLOW_H */ diff --git a/src/audacious/equalizer_preset.c b/src/audacious/equalizer_preset.c index 18652b8..60ecdba 100644 --- a/src/audacious/equalizer_preset.c +++ b/src/audacious/equalizer_preset.c @@ -26,8 +26,8 @@ #include "main.h" #include "plugin.h" #include "rcfile.h" +#include "equalizer.h" #include "equalizer_preset.h" -#include "equalizer_flow.h" EqualizerPreset * equalizer_preset_new(const gchar * name) diff --git a/src/audacious/flow.h b/src/audacious/flow.h index d66a4ba..f5b9963 100644 --- a/src/audacious/flow.h +++ b/src/audacious/flow.h @@ -20,13 +20,13 @@ * Audacious or using our public API to be a derived work. */ +#ifndef AUDACIOUS_FLOW_H +#define AUDACIOUS_FLOW_H + #include <glib.h> #include <mowgli.h> -#include "output.h" - -#ifndef AUDACIOUS_FLOW_H -#define AUDACIOUS_FLOW_H +#include <libaudcore/audio.h> typedef struct { gint time; diff --git a/src/audacious/folder-add.c b/src/audacious/folder-add.c index 30308af..f6ae0d0 100644 --- a/src/audacious/folder-add.c +++ b/src/audacious/folder-add.c @@ -83,11 +83,6 @@ static void show_done (void) gtk_widget_destroy (add_window); } -static gint compare (const void * * a, const void * * b) -{ - return string_compare (* (const gchar * *) a, * (const gchar * *) b); -} - static gboolean add_cb (void * unused) { static GList * stack = NULL; @@ -113,7 +108,8 @@ static gboolean add_cb (void * unused) { gchar * filename = g_filename_to_uri (stack->data, NULL, NULL); - if (filename != NULL && file_probe (filename, TRUE) != NULL) + if (filename != NULL && file_find_decoder (filename, TRUE) != + NULL) index_append (index, filename); else g_free (filename); @@ -159,7 +155,8 @@ static gboolean add_cb (void * unused) if (stack == NULL) { - index_sort (index, compare); + index_sort (index, (gint (*) (const void *, const void *)) + string_compare); count = playlist_count (); @@ -180,7 +177,7 @@ static gboolean add_cb (void * unused) if (add_at > 0) playlist_set_position (add_playlist, add_at); - + playback_initiate (); } diff --git a/src/audacious/images/audacious_player.xpm b/src/audacious/images/audacious_player.xpm index ef31506..f850210 100644 --- a/src/audacious/images/audacious_player.xpm +++ b/src/audacious/images/audacious_player.xpm @@ -1,221 +1,165 @@ /* XPM */ static char * audacious_player_xpm[] = { -"48 48 170 2", +"48 48 114 2", " c None", -". c #EBEBEB", -"+ c #E4E4E4", -"@ c #DDDDDD", -"# c #D6D6D6", -"$ c #D0D0D0", -"% c #CCCCCC", -"& c #EAEAEA", -"* c #CDCDCD", -"= c #BBBBBB", -"- c #AAAAAA", -"; c #9D9D9D", -"> c #939393", -", c #8A8A8A", -"' c #858585", -") c #E8E8E8", -"! c #D3D3D3", -"~ c #A0A0A0", -"{ c #878787", -"] c #6E6E6E", -"^ c #5A5A5A", -"/ c #4D4D4D", -"( c #454545", -"_ c #3E3E3E", -": c #3B3B3B", -"< c #ECECEC", -"[ c #D7D7D7", -"} c #B9B9B9", -"| c #949494", -"1 c #707070", -"2 c #535353", -"3 c #3D3D3D", -"4 c #2B2B2B", -"5 c #1E1E1E", -"6 c #171717", -"7 c #131313", -"8 c #111111", -"9 c #101010", -"0 c #C4C4C4", -"a c #9C9C9C", -"b c #717171", -"c c #4B4B4B", -"d c #2E2E2E", -"e c #1C1C1C", -"f c #0A0A0A", -"g c #060606", -"h c #040404", -"i c #030303", -"j c #B7B7B7", -"k c #555555", -"l c #313131", -"m c #1A1A1A", -"n c #0C0C0C", -"o c #020202", -"p c #050505", -"q c #080808", -"r c #0B0B0B", -"s c #D8D8D8", -"t c #ADADAD", -"u c #777777", -"v c #444444", -"w c #212121", +". c #000000", +"+ c #202020", +"@ c #5E5E5E", +"# c #909090", +"$ c #B1B1B1", +"% c #CACACA", +"& c #D5D5D5", +"* c #B0B0B0", +"= c #8E8E8E", +"- c #5A5A5A", +"; c #1D1D1D", +"> c #030303", +", c #4D4D4D", +"' c #A8A8A8", +") c #D9D9D9", +"! c #D8D8D8", +"~ c #A4A4A4", +"{ c #484848", +"] c #020202", +"^ c #3C3C3C", +"/ c #B8B8B8", +"( c #B5B5B5", +"_ c #393939", +": c #090909", +"< c #858585", +"[ c #828282", +"} c #070707", +"| c #141414", +"1 c #AEAEAE", +"2 c #ADADAD", +"3 c #121212", +"4 c #B9B9B9", +"5 c #ABABAB", +"6 c #AAAAAA", +"7 c #080808", +"8 c #D0D0D0", +"9 c #BCBCBC", +"0 c #CBCBCB", +"a c #818181", +"b c #3A3A3A", +"c c #8C8C8C", +"d c #535353", +"e c #414141", +"f c #2D2D2D", +"g c #010101", +"h c #161616", +"i c #4E4E4E", +"j c #9E9E9E", +"k c #373737", +"l c #B6B6B6", +"m c #313131", +"n c #B4B4B4", +"o c #9A9A9A", +"p c #0C0C0C", +"q c #474747", +"r c #A6A6A6", +"s c #939393", +"t c #282828", +"u c #A5A5A5", +"v c #1F1F1F", +"w c #D6D6D6", "x c #0E0E0E", -"y c #070707", -"z c #2C2C2C", -"A c #363636", -"B c #434343", -"C c #D9D9D9", -"D c #A9A9A9", -"E c #6D6D6D", -"F c #191919", -"G c #090909", -"H c #2F2F2F", -"I c #696969", -"J c #888888", -"K c #A6A6A6", -"L c #B5B5B5", -"M c #BABABA", -"N c #DEDEDE", -"O c #AEAEAE", -"P c #161616", -"Q c #121212", -"R c #585858", -"S c #D1D1D1", -"T c #898989", -"U c #E5E5E5", -"V c #B8B8B8", -"W c #767676", -"X c #3A3A3A", -"Y c #151515", -"Z c #464646", -"` c #808080", -" . c #C0C0C0", -".. c #BFBFBF", -"+. c #C7C7C7", -"@. c #A1A1A1", -"#. c #D5D5D5", -"$. c #DADADA", -"%. c #545454", -"&. c #1F1F1F", -"*. c #202020", -"=. c #5C5C5C", -"-. c #B1B1B1", -";. c #0D0D0D", -">. c #B2B2B2", -",. c #969696", -"'. c #494949", -"). c #A2A2A2", -"!. c #A3A3A3", -"~. c #818181", -"{. c #C5C5C5", -"]. c #474747", -"^. c #C6C6C6", -"/. c #E1E1E1", -"(. c #505050", -"_. c #181818", -":. c #141414", -"<. c #575757", -"[. c #C2C2C2", -"}. c #000000", -"|. c #515151", -"1. c #D2D2D2", -"2. c #383838", -"3. c #A7A7A7", -"4. c #262626", -"5. c #484848", -"6. c #BCBCBC", -"7. c #9A9A9A", -"8. c #393939", -"9. c #BDBDBD", -"0. c #E9E9E9", -"a. c #AFAFAF", -"b. c #1B1B1B", -"c. c #5F5F5F", -"d. c #E2E2E2", -"e. c #272727", -"f. c #8E8E8E", -"g. c #333333", -"h. c #8C8C8C", -"i. c #DBDBDB", -"j. c #959595", -"k. c #404040", -"l. c #010101", -"m. c #303030", -"n. c #ACACAC", -"o. c #ABABAB", -"p. c #7B7B7B", -"q. c #373737", -"r. c #606060", -"s. c #919191", -"t. c #424242", -"u. c #7C7C7C", -"v. c #A5A5A5", -"w. c #353535", -"x. c #525252", -"y. c #343434", -"z. c #D4D4D4", -"A. c #666666", -"B. c #7E7E7E", -"C. c #C1C1C1", -"D. c #C9C9C9", -"E. c #8F8F8F", -"F. c #3F3F3F", -"G. c #CACACA", -"H. c #757575", -"I. c #636363", -"J. c #C8C8C8", -"K. c #848484", -"L. c #A8A8A8", -"M. c #929292", -" ", -" . + @ # $ % % $ # @ + . ", -" & @ * = - ; > , ' ' , > ; - = * @ & ", -" ) ! = ~ { ] ^ / ( _ : : _ ( / ^ ] { ~ = ! ) ", -" < [ } | 1 2 3 4 5 6 7 8 9 9 8 7 6 5 4 3 2 1 | } [ < ", -" + 0 a b c d e 8 f g h i i i i i i h g f 8 e d c b a 0 + ", -" @ j ' k l m n g i o h p g q r r q g p h o i g n m l k ' j @ ", -" s t u v w x g i i y 9 5 z A 3 B B 3 A z 5 9 y i i g x w v u t s ", -" C D E : F G i i q 6 H c I J K L M M L K J I c H 6 q i i G F : E D C ", -" N O ] A P y o h Q d R , M S C s C C C C s C S M T R d Q h o y P A ] O N ", -" U V W X Y g o g m Z ` .s C C C s C C C C s C C C s ..` Z m g o g Y X W V U ", -" +.' B F g o y w k @.#.C C $.C C C C C C C C C C $.C C #.@.k w y o g F B ' +. ", -" $.; %.&.q o g *.=.-.s $.$.C s C C C C C C C C C C s C $.$.s -.=.*.g o q &.%.; $. ", -" . = b H ;.o h m %.>.C C $.C C C C $.C s C C s C $.C C C C $.C C -.%.m h o ;.H b = . ", -" s ,.'.6 p o 9 ( ).s $.C C C $.C C C C C C C C C C C C $.C C C $.s !.( 9 o p 6 '.,.s ", -" ..1 4 f o g z ~.#.$.$.C C C C C {.!.| ] / ].^ ' ^.C C C C C C $.$.#.~.z g o f 4 1 .. ", -" /.!.(._.h i :.<.[.C C C C C C C u i }.}.}.}.}.}.}.i |.{.C C C C C C C [.<.:.i h _.(.!./. ", -" 1.{ 2.x o p 4 , [ C C $.C s C 3.}.}.}.}.}.}.}.}.}.}.}.:.M C s C $.C C [ , 4 p o x 2.{ 1. ", -" .E 4.q o x 5.6.C s s C C C C 7.}.}.}.}.}.}.}.}.}.}.}.}.8.C C C C s s C 9.5.x o q 4.E . ", -" 0.a.<.F h o b.I ! C s s C C C C C b _ ^ c.c.(.h }.}.}.}.}.}.6.C C C s s C ! I b.o h F <.a.0. ", -" d.@.'.Q o i e.f.C C s s $.C C C C C C C C C s g.}.}.}.}.}.}.h.C C $.s s C C f.e.i o Q '.@.d. ", -" i.j.k.x l.h m.n.C C C C C C C C C C # o.p.q.8 }.}.}.}.}.}.}.r.C C C C C C C o.m.h l.x k.j.i. ", -" # h.X ;.l.g 2.= C C C C C C C C C s.Q }.}.}.}.}.}.}.}.}.}.}.t.C C C C C C C M 2.g l.;.X h.# ", -" 1.{ A n l.q _ ..C C s $.C C C C u.}.}.}.}.}.}.}.}.}.}.}.}.}.3 C C C $.s C C ._ q l.n A { 1. ", -" 1.{ A n l.q _ .C C s $.C C C v.o }.}.}.}.}.}.}.}.}.}.}.}.}.E C C C $.s C C ._ q l.n A { 1. ", -" # h.X ;.l.g 2.= C C C C C C C w.}.}.}.}.}.z M M &.}.}.}.}.}.{ C C C C C C C = 2.g l.;.X h.# ", -" i.j.k.x l.h m.t C C C C C C C 4 }.}.}.}.}.x.C [ e.}.}.}.}.}.).C C C C C C C t m.h l.x k.j.i. ", -" d.@.'.Q o i e.s.C C s s $.C C m.}.}.}.}.}.i 8.y.}.}.}.}.}.}.D C C $.s s C C s.e.i o Q '.@.d. ", -" 0.a.<.F h o b.I z.C s s C C C A.}.}.}.}.}.}.}.}.}.}.}.}.}.}.` C C C s s C #.I b.o h F <.a.0. ", -" .E 4.q o x 5. .C s s C C C = g }.}.}.}.}.}.}.}.}.}.}.}.}.B.C C C s s C C.5.x o q 4.E . ", -" 1.{ 2.x o p 4 f.s C C $.C s C ,.r }.}.}.}.}.i w G }.}.}.b.D.s C $.C C s E.4 p o x 2.{ 1. ", -" /.!.(._.h i :.<.^.C C C C C C C M Z y }.F.j.$ C G.H.v I.J.C C C C C C {.<.:.i h _.(.!./. ", -" ..1 4 f o g z K.# $.$.C C C C C C $ 0 C C C C C C C C C C C C $.$.# K.z g o f 4 1 .. ", -" s ,.'.6 p o 9 ( L.C $.C C C $.C C C C C C C C C C C C $.C C C $.C L.( 9 o p 6 '.,.s ", -" . = b H ;.o h m %.V C C $.C C C C $.C s C C s C $.C C C C $.C C j %.m h o ;.H b = . ", -" $.; %.&.q o g *.=.} s $.$.C s C C C C C C C C C C s C $.$.s V =.*.g o q &.%.; $. ", -" +.' B F g o y w k L.[ C C $.C C C C C C C C C C $.C C [ L.k w y o g F B ' +. ", -" U V W X Y g o g m Z ' ^.C C C C s C C C C s C C C C ^.K.Z m g o g Y X W V U ", -" N O ] A P y o h Q d R s.C.#.C s C C C C s C #. .E.R d Q h o y P A ] O N ", -" C D E : F G i i q 6 H c I M.t = . .= t s.I c H 6 q i i G F : E D C ", -" s t u v w x g i i y 9 5 z A 3 B B 3 A z 5 9 y i i g x w v u t s ", -" @ j ' k l m n g i o h p g q r r q g p h o i g n m l k ' j @ ", -" + 0 a b c d e 8 f g h i i i i i i h g f 8 e d c b a 0 + ", -" < [ } | 1 2 3 4 5 6 7 8 9 9 8 7 6 5 4 3 2 1 | } [ < ", -" ) ! = ~ { ] ^ / ( _ : : _ ( / ^ ] { ~ = ! ) ", -" & @ * = - ; > , ' ' , > ; - = * @ & ", -" . + @ # $ % % $ # @ + . ", -" "}; +"y c #2B2B2B", +"z c #1B1B1B", +"A c #A9A9A9", +"B c #1C1C1C", +"C c #5B5B5B", +"D c #464646", +"E c #777777", +"F c #595959", +"G c #8D8D8D", +"H c #CFCFCF", +"I c #929292", +"J c #6D6D6D", +"K c #111111", +"L c #494949", +"M c #5D5D5D", +"N c #353535", +"O c #242424", +"P c #757575", +"Q c #C9C9C9", +"R c #D4D4D4", +"S c #404040", +"T c #D3D3D3", +"U c #ACACAC", +"V c #B2B2B2", +"W c #CCCCCC", +"X c #646464", +"Y c #737373", +"Z c #A3A3A3", +"` c #131313", +" . c #8B8B8B", +".. c #7B7B7B", +"+. c #212121", +"@. c #505050", +"#. c #1E1E1E", +"$. c #050505", +"%. c #5C5C5C", +"&. c #969696", +"*. c #191919", +"=. c #101010", +"-. c #BDBDBD", +";. c #B7B7B7", +">. c #878787", +",. c #898989", +"'. c #343434", +"). c #1A1A1A", +"!. c #BBBBBB", +"~. c #3B3B3B", +"{. c #C2C2C2", +"]. c #838383", +"^. c #808080", +"/. c #AFAFAF", +" . . . . . . . . . . ", +" . . . . . . . . . . . . . . . . ", +" . . . . . . . . . . . . . . . . . . . . . . ", +" . . . . . . . . . . . . . . . . . . . . . . . . ", +" . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +" . . . . . . . . . . + @ # $ % & & % * = - ; . . . . . . . . . . ", +" . . . . . . . . > , ' ) ) ) ) ) ) ) ) ) ) ) ! ~ { ] . . . . . . . . ", +" . . . . . . . . ^ / ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ( _ . . . . . . . . ", +" . . . . . . . : < ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) [ } . . . . . . . ", +" . . . . . . . | 1 ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) 2 | . . . . . . . ", +" . . . . . . 3 4 ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) / 3 . . . . . . ", +" . . . . . . : 5 ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) 6 7 . . . . . . ", +" . . . . . . . [ ) ) ) ) ) ) ) ) ) ) ) ) 8 9 9 0 ) ) ) ) ) ) ) ) ) ) ) ) a . . . . . . . ", +" . . . . . . b ) ) ) ) ) ) ) ) ! c d e f g . . . h i j ) ) ) ) ) ) ) ) ) ) k . . . . . . ", +" . . . . . ] l ) ) ) ) ) ) ) ! d . . . . . . . . . . . m n ) ) ) ) ) ) ) ) ( ] . . . . . ", +" . . . . . . { ) ) ) ) ) ) ) ) o . . . . . . . . . . . . . p 2 ) ) ) ) ) ) ) ) q . . . . . . ", +" . . . . . . r ) ) ) ) ) ) ) ) s . . . . . . . . . . . . . . t ! ) ) ) ) ) ) ) u . . . . . . ", +" . . . . . v ! ) ) ) ) ) ) ) ) w d x ; y y y z . . . . . . . . A ) ) ) ) ) ) ) ! B . . . . . ", +". . . . . . C ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) D . . . . . . . E ) ) ) ) ) ) ) ) F . . . . . . ", +". . . . . . G ) ) ) ) ) ) ) ) ) ) ) ) ) ) H I J K . . . . . . . L ) ) ) ) ) ) ) ) c . . . . . . ", +". . . . . . $ ) ) ) ) ) ) ) ) ) ) ) 6 M N : . . . . . . . . . . O ) ) ) ) ) ) ) ) * . . . . . . ", +". . . . . . 0 ) ) ) ) ) ) ) ) ) ! P > . . . . . . . . . . . . . : ) ) ) ) ) ) ) ) Q . . . . . . ", +". . . . . . R ) ) ) ) ) ) ) ) ) - . . . . . . . . . . . . . . . : ) ) ) ) ) ) ) ) R . . . . . . ", +". . . . . . R ) ) ) ) ) ) ) ) < . . . . . . . . . . . . . . . . S ) ) ) ) ) ) ) ) R . . . . . . ", +". . . . . . 0 ) ) ) ) ) ) ) T p . . . . . . D 2 U m . . . . . . F ) ) ) ) ) ) ) ) Q . . . . . . ", +". . . . . . V ) ) ) ) ) ) ) W . . . . . . . G ) ) X . . . . . . Y ) ) ) ) ) ) ) ) * . . . . . . ", +". . . . . . # ) ) ) ) ) ) ) W . . . . . . . k 5 Z ` . . . . . . .) ) ) ) ) ) ) ) G . . . . . . ", +". . . . . . M ) ) ) ) ) ) ) w x . . . . . . . . . . . . . . . . ..) ) ) ) ) ) ) ) C . . . . . . ", +" . . . . . +.) ) ) ) ) ) ) ) @.. . . . . . . . . . . . . . . . q ) ) ) ) ) ) ) ) #.. . . . . ", +" . . . . . . A ) ) ) ) ) ) ) V $.. . . . . . . . . . . . . . . %.) ) ) ) ) ) ) ' . . . . . . ", +" . . . . . . , ) ) ) ) ) ) ) ) &.p . . . . . . > *.K . . . . =.-.) ) ) ) ) ) ) , . . . . . . ", +" . . . . . > ;.) ) ) ) ) ) ) ) -.^ ] . . m >.% ) w ,.'.).{ !.) ) ) ) ) ) ) l > . . . . . ", +" . . . . . . ~.) ) ) ) ) ) ) ) ) ) {. .~ ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) _ . . . . . . ", +" . . . . . . . ].) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) a . . . . . . . ", +" . . . . . . : 6 ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) 6 7 . . . . . . ", +" . . . . . . 3 / ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) / 3 . . . . . . ", +" . . . . . . . | 1 ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) U 3 . . . . . . . ", +" . . . . . . . } [ ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ^.} . . . . . . . ", +" . . . . . . . . b ;.) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) n k . . . . . . . . ", +" . . . . . . . . > , ' ) ) ) ) ) ) ) ) ) ) ) ! ~ { ] . . . . . . . . ", +" . . . . . . . . . . v C = /.Q R R Q 1 c F B . . . . . . . . . . ", +" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +" . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +" . . . . . . . . . . . . . . . . . . . . . . . . ", +" . . . . . . . . . . . . . . . . . . . . . . ", +" . . . . . . . . . . . . . . . . ", +" . . . . . . . . . . "}; diff --git a/src/audacious/input.c b/src/audacious/input.c index ae3bf75..c5a6025 100644 --- a/src/audacious/input.c +++ b/src/audacious/input.c @@ -31,8 +31,8 @@ #include <mowgli.h> #include "input.h" +#include "output.h" #include "plugin-registry.h" -#include "probe.h" PlaybackData ip_data = { @@ -73,133 +73,6 @@ GList * get_input_list (void) return list; } -Tuple * -input_get_song_tuple(const gchar * filename) -{ - InputPlugin *ip = NULL; - Tuple *input = NULL; - gchar *ext = NULL; - - if (filename == NULL) - return NULL; - - ip = file_probe (filename, FALSE); - - if (ip && ip->get_song_tuple) - input = ip->get_song_tuple (filename); - else - { - gchar *scratch; - - scratch = uri_to_display_basename(filename); - tuple_associate_string(input, FIELD_FILE_NAME, NULL, scratch); - g_free(scratch); - - scratch = uri_to_display_dirname(filename); - tuple_associate_string(input, FIELD_FILE_PATH, NULL, scratch); - g_free(scratch); - - ext = strrchr(filename, '.'); - if (ext != NULL) { - ++ext; - tuple_associate_string(input, FIELD_FILE_EXT, NULL, ext); - } - - tuple_associate_int(input, FIELD_LENGTH, NULL, -1); - } - - return input; -} - -static void -input_general_file_info_box(const gchar * filename, InputPlugin * ip) -{ - GtkWidget *window, *vbox; - GtkWidget *label, *filename_hbox, *filename_entry; - GtkWidget *bbox, *cancel; - - gchar *title, *fileinfo, *basename, *iplugin; - gchar *filename_utf8; - gchar *realfn = NULL; - - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_resizable(GTK_WINDOW(window), FALSE); - gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); - - realfn = g_filename_from_uri(filename, NULL, NULL); - basename = g_path_get_basename(realfn ? realfn : filename); - fileinfo = filename_to_utf8(basename); - title = g_strdup_printf(_("audacious: %s"), fileinfo); - - gtk_window_set_title(GTK_WINDOW(window), title); - - g_free(title); - g_free(fileinfo); - g_free(basename); - - gtk_container_set_border_width(GTK_CONTAINER(window), 10); - - vbox = gtk_vbox_new(FALSE, 10); - gtk_container_add(GTK_CONTAINER(window), vbox); - - filename_hbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(vbox), filename_hbox, FALSE, TRUE, 0); - - label = gtk_label_new(_("Filename:")); - gtk_box_pack_start(GTK_BOX(filename_hbox), label, FALSE, TRUE, 0); - - filename_entry = gtk_entry_new(); - filename_utf8 = filename_to_utf8(realfn ? realfn : filename); - g_free(realfn); realfn = NULL; - - gtk_entry_set_text(GTK_ENTRY(filename_entry), filename_utf8); - gtk_editable_set_editable(GTK_EDITABLE(filename_entry), FALSE); - gtk_box_pack_start(GTK_BOX(filename_hbox), filename_entry, TRUE, TRUE, 0); - - g_free(filename_utf8); - - if (ip) - if (ip->description) - iplugin = ip->description; - else - iplugin = ip->filename; - else - iplugin = _("No input plugin recognized this file"); - - title = g_strdup_printf(_("Input plugin: %s"), iplugin); - - label = gtk_label_new(title); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); - g_free(title); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0); - - bbox = gtk_hbutton_box_new(); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); - gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); - - cancel = gtk_button_new_from_stock(GTK_STOCK_CLOSE); - g_signal_connect_swapped(G_OBJECT(cancel), "clicked", - G_CALLBACK(gtk_widget_destroy), - window); - GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); - gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); - - gtk_widget_show_all(window); -} - -void input_file_info_box (const gchar * filename) -{ - InputPlugin * decoder; - - decoder = file_probe (filename, FALSE); - - if (decoder != NULL && decoder->file_info_box != NULL) - decoder->file_info_box (filename); - else - input_general_file_info_box (filename, decoder); -} - void input_get_volume(gint * l, gint * r) { diff --git a/src/audacious/input.h b/src/audacious/input.h index b5afb90..2ca35f5 100644 --- a/src/audacious/input.h +++ b/src/audacious/input.h @@ -52,11 +52,8 @@ InputPlayback *get_current_input_playback(void); void set_current_input_playback(InputPlayback * ip); void set_current_input_data(void * data); -Tuple *input_get_song_tuple(const gchar * filename); - void input_get_volume(gint * l, gint * r); void input_set_volume(gint l, gint r); -void input_file_info_box(const gchar * filename); extern PlaybackData ip_data; diff --git a/src/audacious/interface.c b/src/audacious/interface.c index 8400fef..483f84d 100644 --- a/src/audacious/interface.c +++ b/src/audacious/interface.c @@ -21,6 +21,7 @@ #include <glib.h> #include <glib/gi18n.h> +#include <gtk/gtk.h> #include "interface.h" #include "playback.h" @@ -181,8 +182,8 @@ interface_show_about_window(gboolean show) } } -void -interface_run_gtk_plugin(GtkWidget *parent, const gchar *name) +/* void interface_run_gtk_plugin (GtkWidget * parent, const gchar * name) */ +void interface_run_gtk_plugin (void * parent, const gchar * name) { if (interface_cbs.run_gtk_plugin != NULL) interface_cbs.run_gtk_plugin(parent, name); @@ -201,8 +202,8 @@ interface_run_gtk_plugin(GtkWidget *parent, const gchar *name) } } -void -interface_stop_gtk_plugin(GtkWidget *parent) +/* void interface_stop_gtk_plugin (GtkWidget * parent) */ +void interface_stop_gtk_plugin (void * parent) { if (interface_cbs.stop_gtk_plugin != NULL) interface_cbs.stop_gtk_plugin(parent); diff --git a/src/audacious/interface.h b/src/audacious/interface.h index 41e76b8..7430707 100644 --- a/src/audacious/interface.h +++ b/src/audacious/interface.h @@ -29,15 +29,18 @@ #ifndef __AUDACIOUS2_INTERFACE_H__ #define __AUDACIOUS2_INTERFACE_H__ -#include <gtk/gtk.h> #include <mowgli.h> typedef struct { - GtkWidget** (*create_prefs_window)(void); + /* GtkWidget * * (* create_prefs_window) (void); */ + void * * (* create_prefs_window) (void); void (*show_prefs_window)(void); void (*hide_prefs_window)(void); void (*destroy_prefs_window)(void); - gint (*prefswin_page_new)(GtkWidget *container, gchar *name, gchar *imgurl); + /* gint (* prefswin_page_new) (GtkWidget * container, const gchar * name, + const gchar * imgurl); */ + gint (* prefswin_page_new) (void * container, const gchar * name, + const gchar * imgurl); } InterfaceOps; typedef struct { @@ -52,8 +55,10 @@ typedef struct { void (*hide_about_window)(void); void (*toggle_shuffle)(void); void (*toggle_repeat)(void); - GtkWidget *(*run_gtk_plugin)(GtkWidget *parent, const gchar *name); - GtkWidget *(*stop_gtk_plugin)(GtkWidget *parent); + /* GtkWidget * (* run_gtk_plugin) (GtkWidget * parent, const gchar * name); */ + void * (* run_gtk_plugin) (void * parent, const gchar * name); + /* GtkWidget * (* stop_gtk_plugin) (GtkWidget * parent); */ + void * (* stop_gtk_plugin) (void * parent); } InterfaceCbs; typedef struct _Interface { @@ -82,8 +87,10 @@ void interface_hide_filebrowser(void); void interface_toggle_visibility(void); void interface_show_error_message(const gchar * markup); void interface_show_jump_to_track(void); -void interface_run_gtk_plugin(GtkWidget *parent, const gchar *name); -void interface_stop_gtk_plugin(GtkWidget *parent); +/* void interface_run_gtk_plugin (GtkWidget * parent, const gchar * name); */ +void interface_run_gtk_plugin (void * parent, const gchar * name); +/* void interface_stop_gtk_plugin (GtkWidget * parent); */ +void interface_stop_gtk_plugin (void * parent); void interface_toggle_shuffle(void); void interface_toggle_repeat(void); diff --git a/src/audacious/main.c b/src/audacious/main.c index 4c2dc3c..8280303 100644 --- a/src/audacious/main.c +++ b/src/audacious/main.c @@ -43,7 +43,6 @@ #include "eggdesktopfile.h" #endif -#include "build_stamp.h" #include "configdb.h" #include "equalizer.h" #include "hook.h" @@ -58,10 +57,13 @@ #include "util.h" #include "vfs.h" #include "chardet.h" +#include "audtag.h" #include "ui_headless.h" #include "ui_misc.h" +#define AUTOSAVE_INTERVAL 300 /* seconds */ + static const gchar *application_name = N_("Audacious"); struct _AudCmdLineOpt @@ -89,7 +91,7 @@ MprisPlayer *mpris; static void print_version(void) { - g_printf("%s %s [%s]\n", _(application_name), VERSION, build_stamp); + g_printf("%s %s (%s)\n", _(application_name), VERSION, BUILDSTAMP); } static void aud_make_user_dir(void) @@ -133,11 +135,7 @@ static void aud_init_paths() aud_paths[BMP_PATH_PLAYLISTS_DIR] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "playlists", NULL); aud_paths[BMP_PATH_CONFIG_FILE] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "config", NULL); -#ifdef HAVE_XSPF_PLAYLIST aud_paths[BMP_PATH_PLAYLIST_FILE] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "playlist.xspf", NULL); -#else - aud_paths[BMP_PATH_PLAYLIST_FILE] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "playlist.m3u", NULL); -#endif aud_paths[BMP_PATH_ACCEL_FILE] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "accels", NULL); aud_paths[BMP_PATH_LOG_FILE] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "log", NULL); @@ -200,7 +198,7 @@ static void parse_cmd_line_options(gint * argc, gchar *** argv) exit(EXIT_FAILURE); } - g_free(context); + g_option_context_free (context); } static void handle_cmd_line_filenames(gboolean is_running) @@ -352,46 +350,13 @@ static void aud_setup_logger(void) g_atexit(aud_logger_stop); } -static gboolean load_extra_playlist(const gchar * path, const gchar * basename, gpointer def) -{ - gchar * filename = g_filename_to_uri (path, NULL, NULL); - gint playlist = playlist_count(); - - playlist_insert(playlist); - playlist_insert_playlist(playlist, 0, filename); - - g_free (filename); - - return FALSE; /* keep loading other playlists */ -} - -static void playlist_system_init() -{ - gchar * filename = g_filename_to_uri (aud_paths[BMP_PATH_PLAYLIST_FILE], - NULL, NULL); - - playlist_init(); - - if (vfs_file_test (filename, G_FILE_TEST_EXISTS)) - playlist_insert_playlist (0, 0, filename); - - g_free (filename); - - /* Load extra playlists */ - if (!dir_foreach(aud_paths[BMP_PATH_PLAYLISTS_DIR], load_extra_playlist, NULL, NULL)) - g_warning("Could not load extra playlists\n"); - - playlist_load_state (); - playlist_set_shuffle(cfg.shuffle); -} - void aud_quit(void) { Interface *i = interface_get(options.interface); g_message("Saving configuration"); aud_config_save(); - playlist_save_state (); + save_playlists (); if (playback_get_playing ()) playback_stop (); @@ -447,6 +412,14 @@ void init_playback_hooks(void) } #endif +static gboolean autosave_cb (void * unused) +{ + g_message ("Saving configuration.\n"); + aud_config_save (); + save_playlists (); + return TRUE; +} + gint main(gint argc, gchar ** argv) { Interface *i; @@ -463,6 +436,7 @@ gint main(gint argc, gchar ** argv) gdk_threads_init(); mowgli_init(); chardet_init(); + tag_init(); hook_init(); hook_associate("quit", quit_cb, 0); @@ -500,6 +474,7 @@ gint main(gint argc, gchar ** argv) g_message("Loading configuration"); aud_config_load(); + atexit (aud_config_free); g_message("Initializing signal handlers"); signal_handlers_init(); @@ -531,8 +506,9 @@ gint main(gint argc, gchar ** argv) exit(EXIT_SUCCESS); } - playlist_system_init(); - init_equalizer (); + playlist_init (); + load_playlists (); + eq_init (); g_message("Handling commandline options, part #2"); handle_cmd_line_options(); @@ -545,6 +521,8 @@ gint main(gint argc, gchar ** argv) ui_display_unsupported_version_warning(); #endif + g_timeout_add_seconds (AUTOSAVE_INTERVAL, autosave_cb, NULL); + g_message("Selecting interface %s", options.interface); i = interface_get(options.interface); diff --git a/src/audacious/output.c b/src/audacious/output.c index 802eb32..f00dd20 100644 --- a/src/audacious/output.c +++ b/src/audacious/output.c @@ -26,7 +26,7 @@ #include "audio.h" #include "audconfig.h" #include "effect.h" -#include "equalizer_flow.h" +#include "equalizer.h" #include "flow.h" #include "output.h" #include "playback.h" @@ -111,7 +111,6 @@ static void drain (void); /* output_mutex must be locked */ static void real_close (void) { - new_effect_flush (); vis_runner_start_stop (FALSE, FALSE); COP->close_audio (); output_opened = FALSE; @@ -148,36 +147,34 @@ static gboolean output_open_audio (AFormat format, gint rate, gint channels) LOCK; - if (output_leave_open) + if (output_leave_open && COP->set_written_time != NULL) { - if (channels == decoder_channels && rate == decoder_rate && - COP->set_written_time != NULL) - { - vis_runner_time_offset (- frames_written * 1000 / decoder_rate); - COP->set_written_time (0); - output_opened = TRUE; - } - else - { - UNLOCK; - drain (); - LOCK; - real_close (); - } + vis_runner_time_offset (- frames_written * (gint64) 1000 / decoder_rate); + COP->set_written_time (0); } decoder_format = format; decoder_channels = channels; decoder_rate = rate; frames_written = 0; - output_leave_open = FALSE; - output_paused = FALSE; - if (! output_opened) + effect_channels = channels; + effect_rate = rate; + new_effect_start (& effect_channels, & effect_rate); + eq_set_format (effect_channels, effect_rate); + + if (output_leave_open && COP->set_written_time != NULL && effect_channels == + output_channels && effect_rate == output_rate) + output_opened = TRUE; + else { - effect_channels = channels; - effect_rate = rate; - new_effect_start (& effect_channels, & effect_rate); + if (output_leave_open) + { + UNLOCK; + drain (); + LOCK; + real_close (); + } output_format = cfg.output_bit_depth == 32 ? FMT_S32_NE : cfg.output_bit_depth == 24 ? FMT_S24_NE : cfg.output_bit_depth == 16 ? @@ -192,6 +189,9 @@ static gboolean output_open_audio (AFormat format, gint rate, gint channels) } } + output_leave_open = FALSE; + output_paused = FALSE; + UNLOCK; return output_opened; } @@ -200,8 +200,13 @@ static void output_close_audio (void) { LOCK; + output_opened = FALSE; + if (! output_leave_open) + { + new_effect_flush (); real_close (); + } UNLOCK; } @@ -232,7 +237,7 @@ static gint get_written_time (void) LOCK; if (output_opened) - time = frames_written * 1000 / decoder_rate; + time = frames_written * (gint64) 1000 / decoder_rate; UNLOCK; return time; @@ -254,19 +259,6 @@ static gboolean output_buffer_playing (void) return FALSE; } -static Flow * get_postproc_flow (void) -{ - static Flow * flow = NULL; - - if (flow == NULL) - { - flow = flow_new (); - flow_link_element (flow, equalizer_flow); - } - - return flow; -} - static Flow * get_legacy_flow (void) { static Flow * flow = NULL; @@ -358,15 +350,7 @@ static void do_write (void * data, gint samples) { void * allocated = NULL; - samples = flow_execute (get_postproc_flow (), 0, & data, sizeof (gfloat) * - samples, FMT_FLOAT, effect_rate, effect_channels) / sizeof (gfloat); - - if (data != allocated) - { - g_free (allocated); - allocated = NULL; - } - + eq_filter (data, samples); apply_software_volume (data, output_channels, samples / output_channels); if (output_format != FMT_FLOAT) @@ -436,8 +420,8 @@ static void output_write_audio (void * data, gint size) } apply_replay_gain (data, samples); - vis_runner_pass_audio (frames_written * 1000 / decoder_rate, data, samples, - decoder_channels); + vis_runner_pass_audio (frames_written * (gint64) 1000 / decoder_rate, data, + samples, decoder_channels); new_effect_process ((gfloat * *) & data, & samples); if (data != allocated) @@ -461,8 +445,6 @@ static void write_buffers (void) static void drain (void) { - write_buffers (); - if (COP->buffer_playing != NULL) { while (COP->buffer_playing ()) @@ -508,6 +490,7 @@ void output_drain (void) if (output_leave_open) { UNLOCK; + write_buffers (); /* tell effect plugins this is the last song */ drain (); LOCK; real_close (); @@ -530,13 +513,6 @@ void set_current_output_plugin (OutputPlugin * plugin) playback_stop (); } - LOCK; - - if (output_leave_open) - real_close (); - - UNLOCK; - /* This function is also used to restart playback (for example, when resampling is switched on or off), in which case we don't need to do an init cycle. -jlindgren */ diff --git a/src/audacious/playback.c b/src/audacious/playback.c index b1942a0..e19a38a 100644 --- a/src/audacious/playback.c +++ b/src/audacious/playback.c @@ -50,8 +50,9 @@ static void set_params (InputPlayback * playback, const gchar * title, gint length, gint bitrate, gint samplerate, gint channels); -static void set_title (InputPlayback * playback, const gchar * title); static void set_tuple (InputPlayback * playback, Tuple * tuple); +static void set_gain_from_playlist (InputPlayback * playback); + static gboolean playback_segmented_end(gpointer data); static gboolean playback_play_file (gint playlist, gint entry); @@ -60,6 +61,54 @@ static gboolean pause_when_ready; static gint seek_when_ready; static gint ready_source; static gint failed_entries; +static gint set_tuple_source = 0; +static Tuple * tuple_to_be_set = NULL; +static ReplayGainInfo gain_from_playlist; + +static void cancel_set_tuple (void) +{ + if (set_tuple_source != 0) + { + g_source_remove (set_tuple_source); + set_tuple_source = 0; + } + + if (tuple_to_be_set != NULL) + { + tuple_free (tuple_to_be_set); + tuple_to_be_set = NULL; + } +} + +/* clears gain info if tuple == NULL */ +static void read_gain_from_tuple (Tuple * tuple) +{ + gint album_gain, album_peak, track_gain, track_peak, gain_unit, peak_unit; + + memset (& gain_from_playlist, 0, sizeof gain_from_playlist); + + if (tuple == NULL) + return; + + album_gain = tuple_get_int (tuple, FIELD_GAIN_ALBUM_GAIN, NULL); + album_peak = tuple_get_int (tuple, FIELD_GAIN_ALBUM_PEAK, NULL); + track_gain = tuple_get_int (tuple, FIELD_GAIN_TRACK_GAIN, NULL); + track_peak = tuple_get_int (tuple, FIELD_GAIN_TRACK_PEAK, NULL); + gain_unit = tuple_get_int (tuple, FIELD_GAIN_GAIN_UNIT, NULL); + peak_unit = tuple_get_int (tuple, FIELD_GAIN_PEAK_UNIT, NULL); + + if (gain_unit) + { + gain_from_playlist.album_gain = album_gain / (gfloat) gain_unit; + gain_from_playlist.track_gain = track_gain / (gfloat) gain_unit; + } + + if (peak_unit) + { + gain_from_playlist.album_peak = album_peak / (gfloat) peak_unit; + gain_from_playlist.track_peak = track_peak / (gfloat) peak_unit; + } +} static gboolean ready_cb (void * data) { @@ -162,19 +211,20 @@ playback_get_time_real(void) return time; } -gint -playback_get_time(void) +gint playback_get_time (void) { InputPlayback * playback; playback = ip_data.current_input_playback; g_return_val_if_fail (playback != NULL, 0); - return playback_get_time_real() - playback->start; + if (playback->start > 0) + return playback_get_time_real () - playback->start; + else + return playback_get_time_real (); } -void -playback_initiate(void) +void playback_initiate (void) { gint playlist, entry; @@ -241,7 +291,8 @@ void playback_pause (void) hook_call("playback unpause", NULL); if (playback->end > 0) - playback->end_timeout = g_timeout_add(playback_get_time_real() - playback->start, playback_segmented_end, playback); + playback->end_timeout = g_timeout_add (playback->end - + playback_get_time_real (), playback_segmented_end, playback); } } @@ -271,6 +322,7 @@ static void playback_finalize (InputPlayback * playback) playback_free (playback); ip_data.current_input_playback = NULL; + cancel_set_tuple (); if (playback->end_timeout) g_source_remove(playback->end_timeout); @@ -291,16 +343,6 @@ void playback_stop (void) hook_call ("playback stop", NULL); } -static void -run_no_output_plugin_dialog(void) -{ - const gchar *markup = - N_("<b><big>No output plugin selected.</big></b>\n" - "You have not selected an output plugin."); - - interface_show_error_message(markup); -} - static gboolean playback_ended (void * user_data) { gint playlist = playlist_get_playing (); @@ -324,8 +366,7 @@ static gboolean playback_ended (void * user_data) if (! (play = playlist_next_song (playlist, cfg.repeat))) playlist_set_position (playlist, -1); - if (failed_entries >= 100 || failed_entries >= playlist_entry_count - (playlist) * 2) + if (failed_entries >= 10) play = FALSE; } @@ -406,6 +447,10 @@ playback_monitor_thread(gpointer data) static void playback_set_replaygain_info (InputPlayback * playback, ReplayGainInfo * info) { + fprintf (stderr, "Plugin %s should be updated to use OutputAPI::" + "set_replaygain_info or (better) InputPlayback::set_gain_from_playlist.\n", + playback->plugin->description); + playback->output->set_replaygain_info (info); } @@ -413,6 +458,15 @@ static void playback_set_replaygain_info (InputPlayback * playback, static void playback_pass_audio (InputPlayback * playback, AFormat format, gint channels, gint size, void * data, gint * going) { + static gboolean warned = FALSE; + + if (! warned) + { + fprintf (stderr, "Plugin %s should be updated to use OutputAPI::" + "write_audio.\n", playback->plugin->description); + warned = TRUE; + } + playback->output->write_audio (data, size); } @@ -434,8 +488,8 @@ playback_new(void) playback->set_pb_ready = playback_set_pb_ready; playback->set_pb_change = playback_set_pb_change; playback->set_params = set_params; - playback->set_title = set_title; playback->set_tuple = set_tuple; + playback->set_gain_from_playlist = set_gain_from_playlist; /* compatibility */ playback->set_replaygain_info = playback_set_replaygain_info; @@ -484,23 +538,31 @@ static gboolean playback_play_file (gint playlist, gint entry) const gchar * filename = playlist_entry_get_filename (playlist, entry); const gchar * title = playlist_entry_get_title (playlist, entry); InputPlugin * decoder = playlist_entry_get_decoder (playlist, entry); + Tuple * tuple = (Tuple *) playlist_entry_get_tuple (playlist, entry); InputPlayback *playback; - if (current_output_plugin == NULL) - { - run_no_output_plugin_dialog (); - return FALSE; - } - if (decoder == NULL) - decoder = file_probe (filename, FALSE); + decoder = file_find_decoder (filename, FALSE); if (decoder == NULL) { - g_warning("Cannot play %s: no decoder found.\n", filename); + gchar * error = g_strdup_printf (_("No decoder found for %s."), filename); + + interface_show_error_message (error); + g_free (error); return FALSE; } + if (tuple == NULL) + { + tuple = file_read_tuple (filename, decoder); + + if (tuple != NULL) + playlist_entry_set_tuple (playlist, entry, tuple); + } + + read_gain_from_tuple (tuple); /* even if tuple == NULL */ + ip_data.playing = TRUE; ip_data.paused = FALSE; ip_data.stop = FALSE; @@ -524,7 +586,7 @@ static gboolean playback_play_file (gint playlist, gint entry) #endif hook_associate ("playlist update", update_cb, NULL); - hook_call ("playback begin", NULL); + hook_call ("playback begin", playback); return TRUE; } @@ -585,13 +647,6 @@ void playback_seek (gint time) static void set_params (InputPlayback * playback, const gchar * title, gint length, gint bitrate, gint samplerate, gint channels) { - g_return_if_fail (playback != NULL); - - /* deprecated usage */ - if (title != NULL || length != 0) - g_warning ("%s needs to be updated to use InputPlayback::set_tuple\n", - playback->plugin->description); - playback->rate = bitrate; playback->freq = samplerate; playback->nch = channels; @@ -599,25 +654,30 @@ static void set_params (InputPlayback * playback, const gchar * title, gint event_queue ("info change", NULL); } -/* deprecated */ -static void set_title (InputPlayback * playback, const gchar * title) -{ - g_warning ("%s needs to be updated to use InputPlayback::set_tuple\n", - playback->plugin->description); -} - -static gboolean set_tuple_cb (void * tuple) +static gboolean set_tuple_cb (void * unused) { gint playlist = playlist_get_playing (); - playlist_entry_set_tuple (playlist, playlist_get_position (playlist), tuple); + playlist_entry_set_tuple (playlist, playlist_get_position (playlist), + tuple_to_be_set); + set_tuple_source = 0; + tuple_to_be_set = NULL; return FALSE; } static void set_tuple (InputPlayback * playback, Tuple * tuple) { /* playlist_entry_set_tuple must execute in main thread */ - g_timeout_add (0, set_tuple_cb, tuple); + cancel_set_tuple (); + set_tuple_source = g_timeout_add (0, set_tuple_cb, NULL); + tuple_to_be_set = tuple; + + read_gain_from_tuple (tuple); +} + +static void set_gain_from_playlist (InputPlayback * playback) +{ + playback->output->set_replaygain_info (& gain_from_playlist); } gchar * playback_get_title (void) diff --git a/src/audacious/playlist-new.c b/src/audacious/playlist-new.c index 183cca8..635039f 100644 --- a/src/audacious/playlist-new.c +++ b/src/audacious/playlist-new.c @@ -107,7 +107,7 @@ struct entry gint length; gboolean failed; gboolean selected; - gboolean shuffle_num; + gint shuffle_num; gboolean queued; gboolean segmented; gint start; @@ -122,7 +122,7 @@ struct playlist struct index *entries; struct entry *position; gint selected_count; - gint shuffle_num, last_shuffle_num; + gint last_shuffle_num; GList *queued; gint64 total_length; gint64 selected_length; @@ -142,9 +142,6 @@ static Tuple * scan_tuple; static GThread * scan_thread; static gint scan_position, updated_ago; -static gint(*current_filename_compare) (const gchar * a, const gchar * b); -static gint(*current_tuple_compare) (const Tuple * a, const Tuple * b); - static void * scanner (void * unused); static gchar *title_from_tuple(Tuple * tuple) @@ -267,7 +264,7 @@ static void entry_check_has_decoder (struct entry * entry) if (entry->decoder != NULL || entry->failed) return; - entry->decoder = file_probe (entry->filename, TRUE); + entry->decoder = file_find_decoder (entry->filename, TRUE); if (entry->decoder == NULL) entry->failed = TRUE; @@ -283,7 +280,6 @@ static struct playlist *playlist_new(void) playlist->entries = index_new(); playlist->position = NULL; playlist->selected_count = 0; - playlist->shuffle_num = 0; playlist->last_shuffle_num = 0; playlist->queued = NULL; playlist->total_length = 0; @@ -365,27 +361,6 @@ static void queue_update (gint level) NULL); } -static Tuple * get_tuple (const gchar * filename, InputPlugin * decoder) -{ - if (decoder->get_song_tuple != NULL) - return decoder->get_song_tuple (filename); - - if (decoder->probe_for_tuple != NULL) - { - VFSFile * handle = vfs_fopen (filename, "r"); - Tuple * tuple; - - if (handle == NULL) - return NULL; - - tuple = decoder->probe_for_tuple (filename, handle); - vfs_fclose (handle); - return tuple; - } - - return NULL; -} - /* scan_mutex must be locked! */ void scan_receive (void) { @@ -484,7 +459,7 @@ static void * scanner (void * unused) if (scan_filename == NULL) return NULL; - scan_tuple = get_tuple (scan_filename, scan_decoder); + scan_tuple = file_read_tuple (scan_filename, scan_decoder); scan_continue (); } } @@ -500,7 +475,7 @@ static void check_scanned (struct playlist * playlist, struct entry * entry) if (entry->tuple == NULL && ! entry->failed) /* scanner did it for us? */ { - entry_set_tuple (playlist, entry, get_tuple (entry->filename, + entry_set_tuple (playlist, entry, file_read_tuple (entry->filename, entry->decoder)); if (entry->tuple == NULL) @@ -580,6 +555,41 @@ void playlist_insert(gint at) hook_call ("playlist insert", GINT_TO_POINTER (at)); } +void playlist_reorder (gint from, gint to, gint count) +{ + struct index * displaced; + + g_return_if_fail (from >= 0 && from + count <= index_count (playlists)); + g_return_if_fail (to >= 0 && to + count <= index_count (playlists)); + g_return_if_fail (count >= 0); + + PLAYLIST_WILL_CHANGE; + + displaced = index_new (); + + if (to < from) + index_copy_append (playlists, to, displaced, from - to); + else + index_copy_append (playlists, from + count, displaced, to - from); + + index_move (playlists, from, to, count); + + if (to < from) + { + index_copy_set (displaced, 0, playlists, to + count, from - to); + number_playlists (to, from + count - to); + } + else + { + index_copy_set (displaced, 0, playlists, from, to - from); + number_playlists (from, to + count - from); + } + + index_free (displaced); + + PLAYLIST_HAS_CHANGED; +} + void playlist_delete (gint playlist_num) { DECLARE_PLAYLIST; @@ -677,7 +687,10 @@ void playlist_set_playing(gint playlist_num) { DECLARE_PLAYLIST; - LOOKUP_PLAYLIST; + if (playlist_num == -1) + playlist = NULL; + else + LOOKUP_PLAYLIST; if (playing_playlist != NULL && playback_get_playing ()) playback_stop(); @@ -690,8 +703,13 @@ gint playlist_get_playing(void) return (playing_playlist == NULL) ? -1 : playing_playlist->number; } +/* If we are already at the song or it is already at the top of the shuffle + * list, we let it be. Otherwise, we move it to the top. */ static void set_position (struct playlist * playlist, struct entry * entry) { + if (entry == playlist->position) + return; + playlist->position = entry; if (entry == NULL) @@ -702,8 +720,6 @@ static void set_position (struct playlist * playlist, struct entry * entry) playlist->last_shuffle_num ++; entry->shuffle_num = playlist->last_shuffle_num; } - - playlist->shuffle_num = entry->shuffle_num; } gint playlist_entry_count(gint playlist_num) @@ -719,11 +735,11 @@ static void make_entries (gchar * filename, InputPlugin * decoder, Tuple * tuple, struct index * list) { if (tuple == NULL && decoder == NULL) - decoder = file_probe (filename, TRUE); + decoder = file_find_decoder (filename, TRUE); - if (tuple == NULL && decoder != NULL && decoder->have_subtune && - decoder->get_song_tuple != NULL) - tuple = decoder->get_song_tuple (filename); + if (tuple == NULL && decoder != NULL && decoder->have_subtune && strchr + (filename, '?') == NULL) + tuple = file_read_tuple (filename, decoder); if (tuple != NULL && tuple->nsubtunes > 0) { @@ -1290,36 +1306,40 @@ void playlist_randomize(gint playlist_num) PLAYLIST_HAS_CHANGED; } -static gint filename_compare(const void **a, const void **b) +static gint filename_compare (const void * _a, const void * _b, void * _compare) { - const struct entry *entry_a = *a, *entry_b = *b; + const struct entry * a = _a, * b = _b; + gint (* compare) (const gchar * a, const gchar * b) = _compare; - return current_filename_compare(entry_a->filename, entry_b->filename); + return compare (a->filename, b->filename); } -static gint tuple_compare(const void **a, const void **b) +static gint tuple_compare (const void * _a, const void * _b, void * _compare) { - const struct entry *entry_a = *a, *entry_b = *b; + const struct entry * a = _a, * b = _b; + gint (* compare) (const Tuple * a, const Tuple * b) = _compare; - if (entry_a->tuple == NULL) - return (entry_b->tuple == NULL) ? 0 : -1; - if (entry_b->tuple == NULL) + if (a->tuple == NULL) + return (b->tuple == NULL) ? 0 : -1; + if (b->tuple == NULL) return 1; - return current_tuple_compare(entry_a->tuple, entry_b->tuple); + return compare (a->tuple, b->tuple); } -static void sort(struct playlist *playlist, gint(*compare) (const void **a, const void **b)) +static void sort (struct playlist * playlist, gint (* compare) (const void * a, + const void * b, void * inner), void * inner) { PLAYLIST_WILL_CHANGE; - index_sort(playlist->entries, compare); - number_entries(playlist, 0, index_count(playlist->entries)); + index_sort_with_data (playlist->entries, compare, inner); + number_entries (playlist, 0, index_count (playlist->entries)); PLAYLIST_HAS_CHANGED; } -static void sort_selected(struct playlist *playlist, gint(*compare) (const void **a, const void **b)) +static void sort_selected (struct playlist * playlist, gint (* compare) + (const void * a, const void * b, void * inner), void * inner) { gint entries, count, count2; struct index *selected; @@ -1337,7 +1357,7 @@ static void sort_selected(struct playlist *playlist, gint(*compare) (const void index_append(selected, entry); } - index_sort(selected, compare); + index_sort_with_data (selected, compare, inner); count2 = 0; @@ -1355,17 +1375,18 @@ static void sort_selected(struct playlist *playlist, gint(*compare) (const void PLAYLIST_HAS_CHANGED; } -void playlist_sort_by_filename(gint playlist_num, gint(*compare) (const gchar * a, const gchar * b)) +void playlist_sort_by_filename (gint playlist_num, gint (* compare) + (const gchar * a, const gchar * b)) { DECLARE_PLAYLIST; LOOKUP_PLAYLIST; - current_filename_compare = compare; - sort(playlist, filename_compare); + sort (playlist, filename_compare, compare); } -void playlist_sort_by_tuple(gint playlist_num, gint(*compare) (const Tuple * a, const Tuple * b)) +void playlist_sort_by_tuple (gint playlist_num, gint (* compare) + (const Tuple * a, const Tuple * b)) { DECLARE_PLAYLIST; gint entries, count; @@ -1380,21 +1401,21 @@ void playlist_sort_by_tuple(gint playlist_num, gint(*compare) (const Tuple * a, check_scanned (playlist, entry); } - current_tuple_compare = compare; - sort(playlist, tuple_compare); + sort (playlist, tuple_compare, compare); } -void playlist_sort_selected_by_filename(gint playlist_num, gint(*compare) (const gchar * a, const gchar * b)) +void playlist_sort_selected_by_filename (gint playlist_num, gint (* compare) + (const gchar * a, const gchar * b)) { DECLARE_PLAYLIST; LOOKUP_PLAYLIST; - current_filename_compare = compare; - sort_selected(playlist, filename_compare); + sort_selected (playlist, filename_compare, compare); } -void playlist_sort_selected_by_tuple(gint playlist_num, gint(*compare) (const Tuple * a, const Tuple * b)) +void playlist_sort_selected_by_tuple (gint playlist_num, gint (* compare) + (const Tuple * a, const Tuple * b)) { DECLARE_PLAYLIST; gint entries, count; @@ -1410,11 +1431,10 @@ void playlist_sort_selected_by_tuple(gint playlist_num, gint(*compare) (const Tu check_scanned (playlist, entry); } - current_tuple_compare = compare; - sort_selected(playlist, tuple_compare); + sort_selected (playlist, tuple_compare, compare); } -void playlist_reformat_titles() +void playlist_reformat_titles (void) { gint playlist_num; @@ -1459,6 +1479,34 @@ void playlist_rescan(gint playlist_num) METADATA_HAS_CHANGED; } +void playlist_rescan_file (const gchar * filename) +{ + gint num_playlists = index_count (playlists); + gint playlist_num; + + METADATA_WILL_CHANGE; + + for (playlist_num = 0; playlist_num < num_playlists; playlist_num ++) + { + struct playlist * playlist = index_get (playlists, playlist_num); + gint num_entries = index_count (playlist->entries); + gint entry_num; + + for (entry_num = 0; entry_num < num_entries; entry_num ++) + { + struct entry * entry = index_get (playlist->entries, entry_num); + + if (! strcmp (entry->filename, filename)) + { + entry_set_tuple (playlist, entry, NULL); + entry->failed = FALSE; + } + } + } + + METADATA_HAS_CHANGED; +} + gint64 playlist_get_total_length(gint playlist_num) { DECLARE_PLAYLIST; @@ -1477,10 +1525,6 @@ gint64 playlist_get_selected_length(gint playlist_num) return playlist->selected_length; } -void playlist_set_shuffle (gboolean on) /* currently not needed */ -{ -} - gint playlist_queue_count(gint playlist_num) { DECLARE_PLAYLIST; @@ -1610,8 +1654,9 @@ static gboolean shuffle_prev (struct playlist * playlist) { struct entry * entry = index_get (playlist->entries, count); - if (entry->shuffle_num && entry->shuffle_num < playlist->shuffle_num && - (found == NULL || entry->shuffle_num > found->shuffle_num)) + if (entry->shuffle_num && (playlist->position == NULL || + entry->shuffle_num < playlist->position->shuffle_num) && (found == NULL + || entry->shuffle_num > found->shuffle_num)) found = entry; } @@ -1619,7 +1664,6 @@ static gboolean shuffle_prev (struct playlist * playlist) return FALSE; playlist->position = found; - playlist->shuffle_num = found->shuffle_num; return TRUE; } @@ -1629,14 +1673,7 @@ gboolean playlist_prev_song(gint playlist_num) LOOKUP_PLAYLIST_RET (FALSE); - if (playlist->queued != NULL) - { - if (playlist->position == playlist->queued->data) - return FALSE; - - set_position (playlist, playlist->queued->data); - } - else if (cfg.shuffle) + if (cfg.shuffle) { if (! shuffle_prev (playlist)) return FALSE; @@ -1670,15 +1707,15 @@ static gboolean shuffle_next (struct playlist * playlist) if (! entry->shuffle_num) choice ++; - else if (entry->shuffle_num > playlist->shuffle_num && (found == NULL || - entry->shuffle_num < found->shuffle_num)) + else if (playlist->position != NULL && entry->shuffle_num > + playlist->position->shuffle_num && (found == NULL || entry->shuffle_num + < found->shuffle_num)) found = entry; } if (found != NULL) { playlist->position = found; - playlist->shuffle_num = found->shuffle_num; return TRUE; } @@ -1708,7 +1745,6 @@ static void shuffle_reset (struct playlist * playlist) { gint entries = index_count (playlist->entries), count; - playlist->shuffle_num = 0; playlist->last_shuffle_num = 0; for (count = 0; count < entries; count ++) @@ -1805,7 +1841,6 @@ void playlist_save_state (void) fprintf (handle, "playlist %d\n", playlist_num); fprintf (handle, "position %d\n", playlist_get_position (playlist_num)); - fprintf (handle, "shuffled %d\n", playlist->shuffle_num); fprintf (handle, "last-shuffled %d\n", playlist->last_shuffle_num); for (count = 0; count < entries; count ++) @@ -1855,7 +1890,7 @@ void playlist_load_state (void) { gchar scratch[512]; FILE * handle; - gint playlist_num; + gint playlist_num, obsolete = 0; snprintf (scratch, sizeof scratch, "%s/" STATE_FILE, aud_paths[BMP_PATH_USER_DIR]); @@ -1892,13 +1927,13 @@ void playlist_load_state (void) if (position >= 0 && position < entries) playlist->position = index_get (playlist->entries, position); - if (parse_integer ("shuffled", & playlist->shuffle_num)) + if (parse_integer ("shuffled", & obsolete)) /* compatibility with 2.3 */ parse_next (handle); if (parse_integer ("last-shuffled", & playlist->last_shuffle_num)) parse_next (handle); else /* compatibility with 2.3 beta */ - playlist->last_shuffle_num = playlist->shuffle_num; + playlist->last_shuffle_num = obsolete; for (count = 0; count < entries; count ++) { diff --git a/src/audacious/playlist-new.h b/src/audacious/playlist-new.h index 0234946..92f75b8 100644 --- a/src/audacious/playlist-new.h +++ b/src/audacious/playlist-new.h @@ -50,6 +50,7 @@ void playlist_save_state (void); gint playlist_count (void); void playlist_insert (gint at); +void playlist_reorder (gint from, gint to, gint count); void playlist_delete (gint playlist); void playlist_set_filename (gint playlist, const gchar * filename); @@ -103,14 +104,13 @@ void playlist_sort_selected_by_filename (gint playlist, gint (* compare) (const void playlist_sort_selected_by_tuple (gint playlist, gint (* compare) (const Tuple * a, const Tuple * b)); -void playlist_reformat_titles (); +void playlist_reformat_titles (void); void playlist_rescan (gint playlist); +void playlist_rescan_file (const gchar * filename); gint64 playlist_get_total_length (gint playlist); gint64 playlist_get_selected_length (gint playlist); -void playlist_set_shuffle (gboolean shuffle); - gint playlist_queue_count (gint playlist); void playlist_queue_insert (gint playlist, gint at, gint entry); void playlist_queue_insert_selected (gint playlist, gint at); diff --git a/src/audacious/playlist-utils.c b/src/audacious/playlist-utils.c index ec389fa..430ce30 100644 --- a/src/audacious/playlist-utils.c +++ b/src/audacious/playlist-utils.c @@ -1,6 +1,6 @@ /* * playlist-utils.c - * Copyright 2009 John Lindgren + * Copyright 2009-2010 John Lindgren * * This file is part of Audacious. * @@ -320,3 +320,69 @@ gboolean playlist_save (gint playlist, const gchar * filename) playlist_set_active (last); return TRUE; } + +/* The algorithm is a bit quirky for historical reasons. -jlindgren */ +static gchar * make_playlist_path (gint playlist) +{ + if (! playlist) + return g_strdup (aud_paths[BMP_PATH_PLAYLIST_FILE]); + + return g_strdup_printf ("%s/playlist_%02d.xspf", + aud_paths[BMP_PATH_PLAYLISTS_DIR], 1 + playlist); +} + +void load_playlists (void) +{ + gboolean done = FALSE; + gint count; + + for (count = 0; ! done; count ++) + { + gchar * path = make_playlist_path (count); + + if (g_file_test (path, G_FILE_TEST_EXISTS)) + { + gchar * uri = g_filename_to_uri (path, NULL, NULL); + + if (count) + playlist_insert (count); + + playlist_insert_playlist (count, 0, uri); + g_free (uri); + } + else + done = TRUE; + + g_free (path); + } + + playlist_load_state (); +} + +void save_playlists (void) +{ + gint playlists = playlist_count (); + gboolean done = FALSE; + gint count; + + for (count = 0; ! done; count ++) + { + gchar * path = make_playlist_path (count); + + if (count < playlists) + { + gchar * uri = g_filename_to_uri (path, NULL, NULL); + + playlist_save (count, uri); + g_free (uri); + } + else if (g_file_test (path, G_FILE_TEST_EXISTS)) + remove (path); + else + done = TRUE; + + g_free (path); + } + + playlist_save_state (); +} diff --git a/src/audacious/playlist-utils.h b/src/audacious/playlist-utils.h index e5b8c87..69502ee 100644 --- a/src/audacious/playlist-utils.h +++ b/src/audacious/playlist-utils.h @@ -41,4 +41,7 @@ void playlist_insert_folder (gint playlist, gint at, const gchar * folder); void playlist_insert_folder_v2 (gint playlist, gint at, const gchar * folder, gboolean play); +void save_playlists (void); +void load_playlists (void); + #endif diff --git a/src/audacious/plugin.h b/src/audacious/plugin.h index 5c195b6..01bc054 100644 --- a/src/audacious/plugin.h +++ b/src/audacious/plugin.h @@ -1,5 +1,5 @@ /* Audacious - * Copyright (C) 2005-2009 Audacious team. + * Copyright (C) 2005-2010 Audacious team. * * BMP - Cross-platform multimedia player * Copyright (C) 2003-2004 BMP development team. @@ -40,7 +40,7 @@ #define AUDACIOUS_PLUGIN_H #include <glib.h> -#include <gtk/gtk.h> +#include <gmodule.h> #include "libaudcore/audio.h" #include "libaudcore/audstrings.h" @@ -55,7 +55,6 @@ #include "audacious/preferences.h" #include "audacious/interface.h" #include "audacious/equalizer_preset.h" -#include "libaudtag/audtag.h" //@{ /** Plugin type cast macros */ @@ -65,13 +64,12 @@ #define EFFECT_PLUGIN(x) ((EffectPlugin *)(x)) #define GENERAL_PLUGIN(x) ((GeneralPlugin *)(x)) #define VIS_PLUGIN(x) ((VisPlugin *)(x)) -#define LOWLEVEL_PLUGIN(x) ((LowlevelPlugin *)(x)) //@} //@{ /** Preprocessor defines for different API features */ #define __AUDACIOUS_NEWVFS__ /**< @deprecated define for availability of VFS API. */ -#define __AUDACIOUS_PLUGIN_API__ 13 /**< Current generic plugin API/ABI version, exact match is required for plugin to be loaded. */ +#define __AUDACIOUS_PLUGIN_API__ 14 /**< Current generic plugin API/ABI version, exact match is required for plugin to be loaded. */ #define __AUDACIOUS_INPUT_PLUGIN_API__ 8 /**< Input plugin API version. */ //@} @@ -82,6 +80,12 @@ typedef enum { INPUT_VIS_OFF } InputVisType; +typedef enum { + PLUGIN_MESSAGE_ERROR = 0, + PLUGIN_MESSAGE_OK = 1, + PLUGIN_MESSAGE_DEFERRED = 2 +} PluginMessageResponse; + /** Playlist update signal types */ enum { @@ -101,13 +105,14 @@ enum { PLAYLIST_SORT_SCHEMES }; +#define EQUALIZER_MAX_GAIN 12 + typedef struct _Plugin Plugin; typedef struct _InputPlugin InputPlugin; typedef struct _OutputPlugin OutputPlugin; typedef struct _EffectPlugin EffectPlugin; typedef struct _GeneralPlugin GeneralPlugin; typedef struct _VisPlugin VisPlugin; -typedef struct _LowlevelPlugin LowlevelPlugin; typedef struct _InputPlayback InputPlayback; @@ -134,8 +139,8 @@ typedef struct { gint api_version; /**< API version plugin has been compiled for, this is checked against __AUDACIOUS_PLUGIN_API__ */ gchar *name; /**< Module name */ - GCallback init; - GCallback fini; + void (* init) (void); + void (* fini) (void); Plugin *priv_assoc; InputPlugin **ip_list; /**< List of InputPlugin(s) in this module */ OutputPlugin **op_list; @@ -166,47 +171,62 @@ typedef struct { struct _AudaciousFuncTableV1 { /* VFS */ - VFSFile *(*vfs_fopen)(const gchar *uri, const gchar *mode); - gint (*vfs_fclose)(VFSFile *fd); - VFSFile *(*vfs_dup)(VFSFile *in); - gsize (*vfs_fread)(gpointer ptr, - gsize size, - gsize nmemb, - VFSFile * file); - gsize (*vfs_fwrite)(gconstpointer ptr, - gsize size, - gsize nmemb, - VFSFile *file); - - gint (*vfs_getc)(VFSFile *stream); - gint (*vfs_ungetc)(gint c, - VFSFile *stream); - gchar *(*vfs_fgets)(gchar *s, - gint n, - VFSFile *stream); - - gint (*vfs_fseek)(VFSFile * file, - glong offset, - gint whence); - void (*vfs_rewind)(VFSFile * file); - glong (*vfs_ftell)(VFSFile * file); - gboolean (*vfs_feof)(VFSFile * file); - - gboolean (*vfs_file_test)(const gchar * path, - GFileTest test); - - gboolean (*vfs_is_writeable)(const gchar * path); - gboolean (*vfs_truncate)(VFSFile * file, glong length); - off_t (*vfs_fsize)(VFSFile * file); - gchar *(*vfs_get_metadata)(VFSFile * file, const gchar * field); - - int (*vfs_fprintf)(VFSFile *stream, gchar const *format, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); - - gboolean (*vfs_register_transport)(VFSConstructor *vtable); - void (*vfs_file_get_contents)(const gchar *filename, gchar **buf, gsize *size); - gboolean (*vfs_is_remote)(const gchar * path); - gboolean (*vfs_is_streaming)(VFSFile *file); +#ifdef __GNUC__ +#define WARN_RETURN __attribute__ ((warn_unused_result)) +#else +#define WARN_RETURN +#endif + + VFSFile * (* vfs_fopen) (const gchar * path, const gchar * mode) WARN_RETURN; + VFSFile * (* vfs_dup) (VFSFile * in) WARN_RETURN; + gint (* vfs_fclose) (VFSFile * file); + + gint64 (* vfs_fread) (void * ptr, gint64 size, gint64 nmemb, VFSFile * + file) WARN_RETURN; + gint64 (* vfs_fwrite) (const void * ptr, gint64 size, gint64 nmemb, + VFSFile * file) WARN_RETURN; + + gint (* vfs_getc) (VFSFile * stream) WARN_RETURN; + gint (* vfs_ungetc) (gint c, VFSFile * stream) WARN_RETURN; + gchar * (* vfs_fgets) (gchar * s, gint n, VFSFile * stream) WARN_RETURN; + gboolean (* vfs_feof) (VFSFile * file) WARN_RETURN; + gint (* vfs_fprintf) (VFSFile * stream, gchar const * format, ...) + __attribute__ ((__format__ (__printf__, 2, 3))); + + gint (* vfs_fseek) (VFSFile * file, gint64 offset, gint whence) WARN_RETURN; + void (* vfs_rewind) (VFSFile * file); + glong (* vfs_ftell) (VFSFile * file) WARN_RETURN; + gint64 (* vfs_fsize) (VFSFile * file) WARN_RETURN; + gint (* vfs_ftruncate) (VFSFile * file, gint64 length) WARN_RETURN; + + gboolean (* vfs_fget_le16) (guint16 * value, VFSFile * stream) WARN_RETURN; + gboolean (* vfs_fget_le32) (guint32 * value, VFSFile * stream) WARN_RETURN; + gboolean (* vfs_fget_le64) (guint64 * value, VFSFile * stream) WARN_RETURN; + gboolean (* vfs_fget_be16) (guint16 * value, VFSFile * stream) WARN_RETURN; + gboolean (* vfs_fget_be32) (guint32 * value, VFSFile * stream) WARN_RETURN; + gboolean (* vfs_fget_be64) (guint64 * value, VFSFile * stream) WARN_RETURN; + + gboolean (* vfs_fput_le16) (guint16 value, VFSFile * stream) WARN_RETURN; + gboolean (* vfs_fput_le32) (guint32 value, VFSFile * stream) WARN_RETURN; + gboolean (* vfs_fput_le64) (guint64 value, VFSFile * stream) WARN_RETURN; + gboolean (* vfs_fput_be16) (guint16 value, VFSFile * stream) WARN_RETURN; + gboolean (* vfs_fput_be32) (guint32 value, VFSFile * stream) WARN_RETURN; + gboolean (* vfs_fput_be64) (guint64 value, VFSFile * stream) WARN_RETURN; + + gboolean (* vfs_is_streaming) (VFSFile * file) WARN_RETURN; + gchar * (* vfs_get_metadata) (VFSFile * file, const gchar * field) + WARN_RETURN; + + gboolean (* vfs_file_test) (const gchar * path, GFileTest test) WARN_RETURN; + gboolean (* vfs_is_writeable) (const gchar * path) WARN_RETURN; + gboolean (* vfs_is_remote) (const gchar * path) WARN_RETURN; + + void (* vfs_file_get_contents) (const gchar * filename, guchar * * buf, + gint64 * size); + + void (* vfs_register_transport) (VFSConstructor * vtable); + +#undef WARN_RETURN /* VFS Buffer */ VFSFile *(*vfs_buffer_new)(gpointer data, gsize size); @@ -216,21 +236,6 @@ struct _AudaciousFuncTableV1 { VFSFile *(*vfs_buffered_file_new_from_uri)(const gchar *uri); VFSFile *(*vfs_buffered_file_release_live_fd)(VFSFile *fd); - /* VFS endianess helper functions */ - gboolean (*vfs_fget_le16)(guint16 *value, VFSFile *stream); - gboolean (*vfs_fget_le32)(guint32 *value, VFSFile *stream); - gboolean (*vfs_fget_le64)(guint64 *value, VFSFile *stream); - gboolean (*vfs_fget_be16)(guint16 *value, VFSFile *stream); - gboolean (*vfs_fget_be32)(guint32 *value, VFSFile *stream); - gboolean (*vfs_fget_be64)(guint64 *value, VFSFile *stream); - - gboolean (*vfs_fput_le16)(guint16 value, VFSFile *stream); - gboolean (*vfs_fput_le32)(guint32 value, VFSFile *stream); - gboolean (*vfs_fput_le64)(guint64 value, VFSFile *stream); - gboolean (*vfs_fput_be16)(guint16 value, VFSFile *stream); - gboolean (*vfs_fput_be32)(guint32 value, VFSFile *stream); - gboolean (*vfs_fput_be64)(guint64 value, VFSFile *stream); - /* ConfigDb */ mcs_handle_t *(*cfg_db_open)(void); void (*cfg_db_close)(mcs_handle_t *db); @@ -286,14 +291,8 @@ struct _AudaciousFuncTableV1 { void (* mime_set_plugin) (const gchar * mimetype, InputPlugin * ip); /* Util funcs */ - GtkWidget *(*util_info_dialog)(const gchar * title, const gchar * text, - const gchar * button_text, gboolean modal, - GCallback button_action, - gpointer action_data); gchar *(*util_get_localdir)(void); void (*util_menu_main_show)(gint x, gint y, guint button, guint time); - - gpointer (*smart_realloc)(gpointer ptr, gsize *size); void (*util_add_url_history_entry)(const gchar * url); /* INI funcs */ @@ -321,6 +320,7 @@ struct _AudaciousFuncTableV1 { /* Playlist API II (core) */ gint (* playlist_count) (void); void (* playlist_insert) (gint at); + void (* playlist_reorder) (gint from, gint to, gint count); void (* playlist_delete) (gint playlist); void (* playlist_set_filename) (gint playlist, const gchar * filename); @@ -376,8 +376,6 @@ struct _AudaciousFuncTableV1 { gint64 (* playlist_get_total_length) (gint playlist); gint64 (* playlist_get_selected_length) (gint playlist); - void (* playlist_set_shuffle) (gboolean shuffle); - gint (* playlist_queue_count) (gint playlist); void (* playlist_queue_insert) (gint playlist, gint at, gint entry); void (* playlist_queue_insert_selected) (gint playlist, gint at); @@ -406,7 +404,8 @@ struct _AudaciousFuncTableV1 { gboolean (* playlist_save) (gint playlist, const gchar * filename); void (* playlist_insert_folder) (gint playlist, gint at, const gchar * folder); - void (* save_all_playlists) (void); + void (* playlist_insert_folder_v2) (gint playlist, gint at, const gchar * + folder, gboolean play); /* state vars */ AudConfig *_cfg; @@ -419,8 +418,10 @@ struct _AudaciousFuncTableV1 { void (*hook_call)(const gchar *name, gpointer hook_data); /* PluginMenu API */ - gint (*menu_plugin_item_add)(gint, GtkWidget *); - gint (*menu_plugin_item_remove)(gint, GtkWidget *); + /* gint (* menu_plugin_item_add) (gint menu, GtkWidget * item); */ + gint (* menu_plugin_item_add) (gint menu, void * item); + /* gint (* menu_plugin_item_remove) (gint, GtkWidget * item); */ + gint (* menu_plugin_item_remove) (gint, void * item); /* DRCT API. */ void (*drct_quit) ( void ); @@ -485,18 +486,6 @@ struct _AudaciousFuncTableV1 { gint (*drct_pq_get_position)( gint pos ); gint (*drct_pq_get_queue_position)( gint pos ); - /* FileInfoPopup API */ - GtkWidget *(*fileinfopopup_create)(void); - void (*fileinfopopup_destroy)(GtkWidget* fileinfopopup_win); - void (*fileinfopopup_show_from_tuple)(GtkWidget *fileinfopopup_win, Tuple *tuple); - void (*fileinfopopup_show_from_title)(GtkWidget *fileinfopopup_win, gchar *title); - void (*fileinfopopup_hide)(GtkWidget *filepopup_win, gpointer unused); - - /* InputPlayback */ - InputPlayback *(*playback_new)(void); - void (*playback_free)(InputPlayback *); - void (*playback_run)(InputPlayback *); - /* Flows */ gsize (*flow_execute)(Flow *flow, gint time, gpointer *data, gsize len, AFormat fmt, gint srate, gint channels); @@ -525,7 +514,9 @@ struct _AudaciousFuncTableV1 { void (*calc_mono_pcm)(gint16 dest[2][512], gint16 src[2][512], gint nch); void (*calc_stereo_pcm)(gint16 dest[2][512], gint16 src[2][512], gint nch); - void (* create_widgets_with_domain) (GtkBox * box, PreferencesWidget * + /* void (* create_widgets_with_domain) (GtkBox * box, PreferencesWidget * + widgets, gint amt, const gchar * domain); */ + void (* create_widgets_with_domain) (void * box, PreferencesWidget * widgets, gint amt, const gchar * domain); GList *(*equalizer_read_presets)(const gchar * basename); @@ -535,15 +526,23 @@ struct _AudaciousFuncTableV1 { EqualizerPreset *(*equalizer_read_aud_preset)(const gchar * filename); EqualizerPreset *(*load_preset_file)(const gchar *filename); -// /* Audtag lib functions */ -// Tuple *(*tag_tuple_read)(Tuple* tuple); -// gint (*tag_tuple_write_to_file)(Tuple *tuple); + /* File probing API */ + InputPlugin * (* file_find_decoder) (const gchar * filename, gboolean fast); + Tuple * (* file_read_tuple) (const gchar * filename, InputPlugin * decoder); + gboolean (* file_read_image) (const gchar * filename, InputPlugin * decoder, + void * * data, gint * size); + gboolean (* file_can_write_tuple) (const gchar * filename, InputPlugin * + decoder); + gboolean (* file_write_tuple) (const gchar * filename, InputPlugin * + decoder, Tuple * tuple); + gboolean (* custom_infowin) (const gchar * filename, InputPlugin * decoder); /* Miscellaneous */ - GtkWidget * (* get_plugin_menu) (gint id); + /* GtkWidget * (* get_plugin_menu) (gint id); */ + void * (* get_plugin_menu) (gint id); gchar * (* playback_get_title) (void); - void (* fileinfo_show) (gint playlist, gint entry); - void (* fileinfo_show_current) (void); + void (* save_all_playlists) (void); + gchar * (* get_associated_image_file) (const gchar * filename); /* Interface API */ const Interface * (* interface_get_current) (void); @@ -556,57 +555,52 @@ struct _AudaciousFuncTableV1 { gboolean (* playlist_entry_is_segmented)(gint playlist_num, gint entry_num); gint (* playlist_entry_get_start_time)(gint playlist_num, gint entry_num); gint (* playlist_entry_get_end_time)(gint playlist_num, gint entry_num); - - /* Move to proper place when API can be broken */ - void (* playlist_insert_folder_v2) (gint playlist, gint at, const gchar * - folder, gboolean play); }; /* Convenience macros for accessing the public API. */ -/* public name vtable mapping */ +/* public name vtable mapping */ + #define aud_vfs_fopen _audvt->vfs_fopen -#define aud_vfs_fclose _audvt->vfs_fclose #define aud_vfs_dup _audvt->vfs_dup +#define aud_vfs_fclose _audvt->vfs_fclose #define aud_vfs_fread _audvt->vfs_fread #define aud_vfs_fwrite _audvt->vfs_fwrite #define aud_vfs_getc _audvt->vfs_getc #define aud_vfs_ungetc _audvt->vfs_ungetc #define aud_vfs_fgets _audvt->vfs_fgets +#define aud_vfs_feof _audvt->vfs_feof +#define aud_vfs_fprintf _audvt->vfs_fprintf #define aud_vfs_fseek _audvt->vfs_fseek #define aud_vfs_rewind _audvt->vfs_rewind #define aud_vfs_ftell _audvt->vfs_ftell -#define aud_vfs_feof _audvt->vfs_feof -#define aud_vfs_file_test _audvt->vfs_file_test -#define aud_vfs_is_writeable _audvt->vfs_is_writeable -#define aud_vfs_truncate _audvt->vfs_truncate #define aud_vfs_fsize _audvt->vfs_fsize -#define aud_vfs_get_metadata _audvt->vfs_get_metadata -#define aud_vfs_fprintf _audvt->vfs_fprintf -#define aud_vfs_register_transport _audvt->vfs_register_transport -#define aud_vfs_file_get_contents _audvt->vfs_file_get_contents -#define aud_vfs_is_remote _audvt->vfs_is_remote -#define aud_vfs_is_streaming _audvt->vfs_is_streaming - -#define aud_vfs_buffer_new _audvt->vfs_buffer_new -#define aud_vfs_buffer_new_from_string _audvt->vfs_buffer_new_from_string - -#define aud_vfs_buffered_file_new_from_uri _audvt->vfs_buffered_file_new_from_uri -#define aud_vfs_buffered_file_release_live_fd _audvt->vfs_buffered_file_release_live_fd - +#define aud_vfs_ftruncate _audvt->vfs_ftruncate #define aud_vfs_fget_le16 _audvt->vfs_fget_le16 #define aud_vfs_fget_le32 _audvt->vfs_fget_le32 #define aud_vfs_fget_le64 _audvt->vfs_fget_le64 #define aud_vfs_fget_be16 _audvt->vfs_fget_be16 #define aud_vfs_fget_be32 _audvt->vfs_fget_be32 #define aud_vfs_fget_be64 _audvt->vfs_fget_be64 - #define aud_vfs_fput_le16 _audvt->vfs_fput_le16 #define aud_vfs_fput_le32 _audvt->vfs_fput_le32 #define aud_vfs_fput_le64 _audvt->vfs_fput_le64 #define aud_vfs_fput_be16 _audvt->vfs_fput_be16 #define aud_vfs_fput_be32 _audvt->vfs_fput_be32 #define aud_vfs_fput_be64 _audvt->vfs_fput_be64 +#define aud_vfs_is_streaming _audvt->vfs_is_streaming +#define aud_vfs_get_metadata _audvt->vfs_get_metadata +#define aud_vfs_file_test _audvt->vfs_file_test +#define aud_vfs_is_writeable _audvt->vfs_is_writeable +#define aud_vfs_is_remote _audvt->vfs_is_remote +#define aud_vfs_file_get_contents _audvt->vfs_file_get_contents +#define aud_vfs_register_transport _audvt->vfs_register_transport + +#define aud_vfs_buffer_new _audvt->vfs_buffer_new +#define aud_vfs_buffer_new_from_string _audvt->vfs_buffer_new_from_string + +#define aud_vfs_buffered_file_new_from_uri _audvt->vfs_buffered_file_new_from_uri +#define aud_vfs_buffered_file_release_live_fd _audvt->vfs_buffered_file_release_live_fd /* XXX: deprecation warnings */ #define ConfigDb mcs_handle_t /* Alias for compatibility -- ccr */ @@ -649,9 +643,6 @@ struct _AudaciousFuncTableV1 { #define aud_mime_set_plugin _audvt->mime_set_plugin #define aud_uri_set_plugin _audvt->uri_set_plugin -#define aud_info_dialog _audvt->util_info_dialog -#define audacious_info_dialog _audvt->util_info_dialog -#define aud_smart_realloc _audvt->smart_realloc #define aud_util_add_url_history_entry _audvt->util_add_url_history_entry #define aud_str_to_utf8 _audvt->str_to_utf8 @@ -678,6 +669,7 @@ struct _AudaciousFuncTableV1 { #define aud_playlist_count _audvt->playlist_count #define aud_playlist_insert _audvt->playlist_insert +#define aud_playlist_reorder _audvt->playlist_reorder #define aud_playlist_delete _audvt->playlist_delete #define aud_playlist_set_filename _audvt->playlist_set_filename @@ -726,7 +718,6 @@ struct _AudaciousFuncTableV1 { #define aud_playlist_rescan _audvt->playlist_rescan #define aud_playlist_get_total_length _audvt->playlist_get_total_length #define aud_playlist_get_selected_length _audvt->playlist_get_selected_length -#define aud_playlist_set_shuffle _audvt->playlist_set_shuffle #define aud_playlist_queue_count _audvt->playlist_queue_count #define aud_playlist_queue_insert _audvt->playlist_queue_insert @@ -833,18 +824,8 @@ struct _AudaciousFuncTableV1 { #define audacious_drct_pq_get_position _audvt->drct_pq_get_position #define audacious_drct_pq_get_queue_position _audvt->drct_pq_get_queue_position -#define audacious_fileinfopopup_create _audvt->fileinfopopup_create -#define audacious_fileinfopopup_destroy _audvt->fileinfopopup_destroy -#define audacious_fileinfopopup_show_from_tuple _audvt->fileinfopopup_show_from_tuple -#define audacious_fileinfopopup_show_from_title _audvt->fileinfopopup_show_from_title -#define audacious_fileinfopopup_hide _audvt->fileinfopopup_hide - #define audacious_get_localdir _audvt->util_get_localdir -#define aud_playback_new _audvt->playback_new -#define aud_playback_run _audvt->playback_run -#define aud_playback_free(x) _audvt->playback_free - #define aud_flow_execute _audvt->flow_execute #define aud_flow_new _audvt->flow_new #define aud_flow_link_element _audvt->flow_link_element @@ -894,14 +875,17 @@ struct _AudaciousFuncTableV1 { #define aud_output_plugin_cleanup _audvt->output_plugin_cleanup #define aud_output_plugin_reinit _audvt->output_plugin_reinit +#define aud_file_find_decoder _audvt->file_find_decoder +#define aud_file_read_tuple _audvt->file_read_tuple +#define aud_file_read_image _audvt->file_read_image +#define aud_file_can_write_tuple _audvt->file_can_write_tuple +#define aud_file_write_tuple _audvt->file_write_tuple +#define aud_custom_infowin _audvt->custom_infowin + #define aud_get_plugin_menu _audvt->get_plugin_menu #define aud_playback_get_title _audvt->playback_get_title -#define aud_fileinfo_show _audvt->fileinfo_show -#define aud_fileinfo_show_current _audvt->fileinfo_show_current #define aud_save_all_playlists _audvt->save_all_playlists - -//#define aud_tag_tuple_read _audvt->tag_tuple_read -//#define aud_tag_tuple_write_to_file _audvt->tag_tuple_write +#define aud_get_associated_image_file _audvt->get_associated_image_file #define aud_interface_get_current _audvt->interface_get_current #define aud_interface_toggle_visibility _audvt->interface_toggle_visibility @@ -914,6 +898,7 @@ struct _AudaciousFuncTableV1 { #define aud_playlist_entry_get_start_time _audvt->playlist_entry_get_start_time #define aud_playlist_entry_get_end_time _audvt->playlist_entry_get_end_time + #include "audacious/auddrct.h" /* for multi-file plugins :( */ @@ -959,7 +944,8 @@ G_END_DECLS void (*cleanup) (void); \ void (*about) (void); \ void (*configure) (void); \ - PluginPreferences *settings; + PluginPreferences *settings; \ + PluginMessageResponse (*sendmsg)(gint msgtype, gpointer msgdata); /* Sadly, this is the most we can generalize out of the disparate plugin structs usable with typecasts - descender */ @@ -967,18 +953,6 @@ struct _Plugin { PLUGIN_COMMON_FIELDS }; -/* - * LowlevelPlugin is used for lowlevel system services, such as PlaylistContainers, - * VFSContainers and the like. - * - * They are not GUI visible at this time. - * - * XXX: Is this still in use in 1.4? --nenolod - */ -struct _LowlevelPlugin { - PLUGIN_COMMON_FIELDS -}; - typedef enum { OUTPUT_PLUGIN_INIT_FAIL, OUTPUT_PLUGIN_INIT_NO_DEVICES, @@ -1041,16 +1015,20 @@ struct _EffectPlugin { void (* process) (gfloat * * data, gint * samples); /* A seek is taking place; any buffers should be discarded. */ - void (* flush) (); + void (* flush) (void); /* Exactly like process() except that any buffers should be drained (i.e. - * the data processed and returned). */ + * the data processed and returned). finish() will be called a second time + * at the end of the last song in the playlist. */ void (* finish) (gfloat * * data, gint * samples); /* For effects that change the length of the song, these functions allow the * correct time to be displayed. */ gint (* decoder_to_output_time) (gint time); gint (* output_to_decoder_time) (gint time); + + /* Effects with lowest order (0 to 9) are applied first. */ + gint order; }; struct OutputAPI @@ -1101,12 +1079,6 @@ struct _InputPlayback { void (*set_params) (InputPlayback * playback, const gchar * title, gint length, gint bitrate, gint samplerate, gint channels); - /** - * Set playback entry title. - * @deprecated This function is deprecated, use #set_tuple() instead. - */ - void (*set_title) (InputPlayback * playback, const gchar * title); - void (*pass_audio) (InputPlayback *, AFormat, gint, gint, gpointer, gint *); /* called by input plugin when RG info available --asphyx */ @@ -1123,6 +1095,12 @@ struct _InputPlayback { gint start; gint end; gint end_timeout; + + /* If replay gain settings are stored in the tuple associated with the + * current song, this function can be called (after opening audio) to apply + * those settings. If the settings are changed in a call to set_tuple, this + * function must be called again to apply the updated settings. */ + void (* set_gain_from_playlist) (InputPlayback * playback); }; /** @@ -1175,6 +1153,11 @@ struct _InputPlugin { gboolean (*update_song_tuple)(Tuple *tuple, VFSFile *fd); gint priority; /* 0 = first, 10 = last */ + + /* handle will be NULL if the file could not be opened. This is normal in + * the case of custom URI schemes such as cdda://. */ + gboolean (* get_song_image) (const gchar * filename, VFSFile * handle, + void * * data, gint * size); }; struct _GeneralPlugin { @@ -1203,7 +1186,8 @@ struct _VisPlugin { */ void (*render_freq) (gint16 freq_data[2][256]); - GtkWidget *(*get_widget) (void); + /* GtkWidget * (* get_widget) (void); */ + void * (* get_widget) (void); }; /* undefine the macro -- struct Plugin should be used instead. */ diff --git a/src/audacious/pluginenum.c b/src/audacious/pluginenum.c index 13559f4..9790648 100644 --- a/src/audacious/pluginenum.c +++ b/src/audacious/pluginenum.c @@ -51,6 +51,7 @@ #include "playback.h" #include "playlist-new.h" #include "playlist-utils.h" +#include "probe.h" #include "audstrings.h" #include "util.h" #include "visualization.h" @@ -59,11 +60,12 @@ #include "vfs_buffered_file.h" #include "equalizer_preset.h" -#include "ui_fileinfo.h" -#include "ui_fileinfopopup.h" +#include "ui_albumart.h" #include "ui_plugin_menu.h" #include "ui_preferences.h" +#include <libaudgui/init.h> + const gchar *plugin_dir_list[] = { PLUGINSUBS, @@ -77,47 +79,45 @@ static gpointer get_pvt_data(void); static struct _AudaciousFuncTableV1 _aud_papi_v1 = { .vfs_fopen = vfs_fopen, - .vfs_fclose = vfs_fclose, .vfs_dup = vfs_dup, + .vfs_fclose = vfs_fclose, .vfs_fread = vfs_fread, .vfs_fwrite = vfs_fwrite, .vfs_getc = vfs_getc, .vfs_ungetc = vfs_ungetc, .vfs_fgets = vfs_fgets, + .vfs_feof = vfs_feof, + .vfs_fprintf = vfs_fprintf, .vfs_fseek = vfs_fseek, .vfs_rewind = vfs_rewind, .vfs_ftell = vfs_ftell, - .vfs_feof = vfs_feof, - .vfs_file_test = vfs_file_test, - .vfs_is_writeable = vfs_is_writeable, - .vfs_truncate = vfs_truncate, .vfs_fsize = vfs_fsize, - .vfs_get_metadata = vfs_get_metadata, - .vfs_fprintf = vfs_fprintf, - .vfs_register_transport = vfs_register_transport, - .vfs_file_get_contents = vfs_file_get_contents, - .vfs_is_remote = vfs_is_remote, - .vfs_is_streaming = vfs_is_streaming, - - .vfs_buffer_new = vfs_buffer_new, - .vfs_buffer_new_from_string = vfs_buffer_new_from_string, - - .vfs_buffered_file_new_from_uri = vfs_buffered_file_new_from_uri, - .vfs_buffered_file_release_live_fd = vfs_buffered_file_release_live_fd, - + .vfs_ftruncate = vfs_ftruncate, .vfs_fget_le16 = vfs_fget_le16, .vfs_fget_le32 = vfs_fget_le32, .vfs_fget_le64 = vfs_fget_le64, .vfs_fget_be16 = vfs_fget_be16, .vfs_fget_be32 = vfs_fget_be32, .vfs_fget_be64 = vfs_fget_be64, - .vfs_fput_le16 = vfs_fput_le16, .vfs_fput_le32 = vfs_fput_le32, .vfs_fput_le64 = vfs_fput_le64, .vfs_fput_be16 = vfs_fput_be16, .vfs_fput_be32 = vfs_fput_be32, .vfs_fput_be64 = vfs_fput_be64, + .vfs_is_streaming = vfs_is_streaming, + .vfs_get_metadata = vfs_get_metadata, + .vfs_file_test = vfs_file_test, + .vfs_is_writeable = vfs_is_writeable, + .vfs_is_remote = vfs_is_remote, + .vfs_file_get_contents = vfs_file_get_contents, + .vfs_register_transport = vfs_register_transport, + + .vfs_buffer_new = vfs_buffer_new, + .vfs_buffer_new_from_string = vfs_buffer_new_from_string, + + .vfs_buffered_file_new_from_uri = vfs_buffered_file_new_from_uri, + .vfs_buffered_file_release_live_fd = vfs_buffered_file_release_live_fd, .cfg_db_open = cfg_db_open, .cfg_db_close = cfg_db_close, @@ -139,10 +139,6 @@ static struct _AudaciousFuncTableV1 _aud_papi_v1 = { .uri_set_plugin = input_plugin_add_scheme_compat, .mime_set_plugin = input_plugin_add_mime_compat, - .util_info_dialog = util_info_dialog, - - .smart_realloc = smart_realloc, - .util_add_url_history_entry = util_add_url_history_entry, .str_to_utf8 = cd_str_to_utf8, @@ -156,6 +152,7 @@ static struct _AudaciousFuncTableV1 _aud_papi_v1 = { .playlist_count = playlist_count, .playlist_insert = playlist_insert, + .playlist_reorder = playlist_reorder, .playlist_delete = playlist_delete, .playlist_set_filename = playlist_set_filename, @@ -204,8 +201,6 @@ static struct _AudaciousFuncTableV1 _aud_papi_v1 = { .playlist_get_total_length = playlist_get_total_length, .playlist_get_selected_length = playlist_get_selected_length, - .playlist_set_shuffle = playlist_set_shuffle, - .playlist_queue_count = playlist_queue_count, .playlist_queue_insert = playlist_queue_insert, .playlist_queue_insert_selected = playlist_queue_insert_selected, @@ -307,12 +302,6 @@ static struct _AudaciousFuncTableV1 _aud_papi_v1 = { .drct_pq_get_position = drct_pq_get_position, .drct_pq_get_queue_position = drct_pq_get_queue_position, - .fileinfopopup_create = fileinfopopup_create, - .fileinfopopup_destroy = fileinfopopup_destroy, - .fileinfopopup_show_from_title = fileinfopopup_show_from_title, - .fileinfopopup_show_from_tuple = fileinfopopup_show_from_tuple, - .fileinfopopup_hide = fileinfopopup_hide, - .util_get_localdir = util_get_localdir, .flow_new = flow_new, @@ -349,11 +338,17 @@ static struct _AudaciousFuncTableV1 _aud_papi_v1 = { .equalizer_read_aud_preset = equalizer_read_aud_preset, .load_preset_file = load_preset_file, + .file_find_decoder = file_find_decoder, + .file_read_tuple = file_read_tuple, + .file_read_image = file_read_image, + .file_can_write_tuple = file_can_write_tuple, + .file_write_tuple = file_write_tuple, + .custom_infowin = custom_infowin, + .get_plugin_menu = get_plugin_menu, .playback_get_title = playback_get_title, - .fileinfo_show = ui_fileinfo_show, - .fileinfo_show_current = ui_fileinfo_show_current, - .save_all_playlists = save_all_playlists, + .save_all_playlists = save_playlists, + .get_associated_image_file = get_associated_image_file, .interface_get_current = interface_get_current, .interface_toggle_visibility = interface_toggle_visibility, @@ -370,7 +365,6 @@ static struct _AudaciousFuncTableV1 _aud_papi_v1 = { /*****************************************************************/ -GList *lowlevel_list = NULL; extern GList *vfs_transports; static GStaticPrivate cur_plugin_key = G_STATIC_PRIVATE_INIT; @@ -616,9 +610,17 @@ void plugin2_unload(PluginHeader * header, mowgli_node_t * hlist_node) { if (header->ip_list[i]->cleanup != NULL) header->ip_list[i]->cleanup (); + + g_free (header->ip_list[i]->filename); } } + if (header->op_list != NULL) + { + for (i = 0; header->op_list[i] != NULL; i ++) + g_free (header->op_list[i]->filename); + } + if (header->interface) interface_deregister(header->interface); @@ -728,11 +730,12 @@ static OutputPlugin * output_probe (void) void plugin_system_init(void) { gchar *dir; - GList *node; - LowlevelPlugin *lp; GtkWidget *dialog; gint dirsel = 0; + /* give libaudgui its pointer to the API vector table */ + audgui_init (& _aud_papi_v1); + if (!g_module_supported()) { dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Module loading not supported! Plugins will not be loaded.\n")); @@ -801,16 +804,6 @@ void plugin_system_init(void) if (current_output_plugin == NULL) current_output_plugin = output_probe (); - - for (node = lowlevel_list; node; node = g_list_next(node)) - { - lp = LOWLEVEL_PLUGIN(node->data); - if (lp->init) - { - plugin_set_current((Plugin *) lp); - lp->init(); - } - } } void plugin_system_cleanup(void) @@ -818,7 +811,6 @@ void plugin_system_cleanup(void) EffectPlugin *ep; GeneralPlugin *gp; VisPlugin *vp; - LowlevelPlugin *lp; GList *node; mowgli_node_t *hlist_node; @@ -846,6 +838,8 @@ void plugin_system_cleanup(void) if (ep->cleanup) ep->cleanup(); + + g_free (ep->filename); GDK_THREADS_LEAVE(); while (g_main_context_iteration(NULL, FALSE)); @@ -869,6 +863,8 @@ void plugin_system_cleanup(void) if (gp->cleanup) gp->cleanup(); + g_free (gp->filename); + GDK_THREADS_LEAVE(); while (g_main_context_iteration(NULL, FALSE)); GDK_THREADS_ENTER(); @@ -891,6 +887,8 @@ void plugin_system_cleanup(void) if (vp->cleanup) vp->cleanup(); + g_free (vp->filename); + GDK_THREADS_LEAVE(); while (g_main_context_iteration(NULL, FALSE)); GDK_THREADS_ENTER(); @@ -903,28 +901,6 @@ void plugin_system_cleanup(void) vp_data.vis_list = NULL; } - for (node = lowlevel_list; node; node = g_list_next(node)) - { - lp = LOWLEVEL_PLUGIN(node->data); - if (lp) - { - plugin_set_current((Plugin *) lp); - - if (lp->cleanup) - lp->cleanup(); - - GDK_THREADS_LEAVE(); - while (g_main_context_iteration(NULL, FALSE)); - GDK_THREADS_ENTER(); - } - } - - if (lowlevel_list != NULL) - { - g_list_free(lowlevel_list); - lowlevel_list = NULL; - } - /* XXX: vfs will crash otherwise. -nenolod */ if (vfs_transports != NULL) { diff --git a/src/audacious/preferences.h b/src/audacious/preferences.h index 0a8fddd..62d64c0 100644 --- a/src/audacious/preferences.h +++ b/src/audacious/preferences.h @@ -107,7 +107,9 @@ typedef struct _PreferencesWidget { gboolean horizontal; /* FALSE gives vertical, TRUE gives horizontal separator */ } separator; - GtkWidget *(*populate) (void); /* for WIDGET_CUSTOM --nenolod */ + /* for WIDGET_CUSTOM --nenolod */ + /* GtkWidget * (* populate) (void); */ + void * (* populate) (void); } data; ValueType cfg_type; /* connected value type */ } PreferencesWidget; @@ -140,7 +142,9 @@ typedef struct { gpointer data; /* for internal interface use only */ } PluginPreferences; -void create_widgets_with_domain (GtkBox * box, PreferencesWidget * widgets, gint +/* void create_widgets_with_domain (GtkBox * box, PreferencesWidget * widgets, + gint amt, const gchar * domain); */ +void create_widgets_with_domain (void * box, PreferencesWidget * widgets, gint amt, const gchar * domain); #define create_widgets(b, w, a) create_widgets_with_domain (b, w, a, PACKAGE); diff --git a/src/audacious/probe.c b/src/audacious/probe.c index ea6b7bb..17c4b13 100644 --- a/src/audacious/probe.c +++ b/src/audacious/probe.c @@ -24,6 +24,7 @@ #include <stdio.h> #include <string.h> +#include "playlist-new.h" #include "plugin-registry.h" #include "probe.h" @@ -63,7 +64,8 @@ static gboolean probe_func (InputPlugin * decoder, void * data) if (decoder->is_our_file_from_vfs (state->filename, state->handle)) state->decoder = decoder; - vfs_fseek (state->handle, 0, SEEK_SET); + if (vfs_fseek (state->handle, 0, SEEK_SET)) + ; /* ignore errors; they are normal on streaming */ } else if (decoder->is_our_file != NULL) { @@ -97,7 +99,8 @@ static gboolean probe_func_fast (InputPlugin * decoder, void * data) state->handle)) return FALSE; - vfs_fseek (state->handle, 0, SEEK_SET); + if (vfs_fseek (state->handle, 0, SEEK_SET)) + ; /* ignore errors; they are normal on streaming */ } else if (state->decoder->is_our_file != NULL) { @@ -163,7 +166,7 @@ static void probe_by_content (ProbeState * state) input_plugin_by_priority (probe_func, state); } -InputPlugin * file_probe (const gchar * filename, gboolean fast) +InputPlugin * file_find_decoder (const gchar * filename, gboolean fast) { ProbeState state; @@ -197,3 +200,79 @@ DONE: return state.decoder; } + +Tuple * file_read_tuple (const gchar * filename, InputPlugin * decoder) +{ + if (decoder->get_song_tuple != NULL) + return decoder->get_song_tuple (filename); + + if (decoder->probe_for_tuple != NULL) + { + VFSFile * handle = vfs_fopen (filename, "r"); + Tuple * tuple; + + if (handle == NULL) + return NULL; + + tuple = decoder->probe_for_tuple (filename, handle); + vfs_fclose (handle); + return tuple; + } + + return NULL; +} + +gboolean file_read_image (const gchar * filename, InputPlugin * decoder, + void * * data, gint * size) +{ + VFSFile * handle; + gboolean success; + + if (decoder->get_song_image == NULL) + return FALSE; + + handle = vfs_fopen (filename, "r"); + success = decoder->get_song_image (filename, handle, data, size); + + if (handle != NULL) + vfs_fclose (handle); + + return success; +} + +gboolean file_can_write_tuple (const gchar * filename, InputPlugin * decoder) +{ + return (decoder->update_song_tuple != NULL); +} + +gboolean file_write_tuple (const gchar * filename, InputPlugin * decoder, + Tuple * tuple) +{ + VFSFile * handle; + gboolean success; + + if (decoder->update_song_tuple == NULL) + return FALSE; + + handle = vfs_fopen (filename, "r+"); + + if (handle == NULL) + return FALSE; + + success = decoder->update_song_tuple (tuple, handle); + vfs_fclose (handle); + + if (success) + playlist_rescan_file (filename); + + return success; +} + +gboolean custom_infowin (const gchar * filename, InputPlugin * decoder) +{ + if (decoder->file_info_box == NULL) + return FALSE; + + decoder->file_info_box (filename); + return TRUE; +} diff --git a/src/audacious/probe.h b/src/audacious/probe.h index 5cb6d31..4a6971b 100644 --- a/src/audacious/probe.h +++ b/src/audacious/probe.h @@ -1,6 +1,6 @@ /* * probe.h - * Copyright 2009 John Lindgren + * Copyright 2009-2010 John Lindgren * * This file is part of Audacious. * @@ -24,6 +24,14 @@ #include "plugin.h" -InputPlugin * file_probe (const gchar * filename, gboolean fast); +InputPlugin * file_find_decoder (const gchar * filename, gboolean fast); +Tuple * file_read_tuple (const gchar * filename, InputPlugin * decoder); +gboolean file_read_image (const gchar * filename, InputPlugin * decoder, + void * * data, gint * size); +gboolean file_can_write_tuple (const gchar * filename, InputPlugin * decoder); +gboolean file_write_tuple (const gchar * filename, InputPlugin * decoder, + Tuple * tuple); + +gboolean custom_infowin (const gchar * filename, InputPlugin * decoder); #endif diff --git a/src/audacious/sync-menu.c b/src/audacious/sync-menu.c deleted file mode 100644 index 5757b1c..0000000 --- a/src/audacious/sync-menu.c +++ /dev/null @@ -1,715 +0,0 @@ -/* GTK+ Integration for the Mac OS X Menubar. - * - * Copyright (C) 2007 Pioneer Research Center USA, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include <gtk/gtk.h> - -#ifdef GDK_WINDOWING_QUARTZ - -#include <gdk/gdkkeysyms.h> - -#include <Carbon/Carbon.h> - -#include "sync-menu.h" - - -/* TODO - * - * - Setup shortcuts, possibly transforming ctrl->cmd - * - Sync menus - * - Create on demand? (can this be done with gtk+? ie fill in menu items when the menu is opened) - * - Figure out what to do per app/window... - * - Toggle/radio items - * - */ - -#define GTK_QUARTZ_MENU_CREATOR 'GTKC' -#define GTK_QUARTZ_ITEM_WIDGET 'GWID' - - -static void sync_menu_shell (GtkMenuShell *menu_shell, - MenuRef carbon_menu, - gboolean toplevel); - - -/* - * utility functions - */ - -static GtkWidget * -find_menu_label (GtkWidget *widget) -{ - GtkWidget *label = NULL; - - if (GTK_IS_LABEL (widget)) - return widget; - - if (GTK_IS_CONTAINER (widget)) - { - GList *children; - GList *l; - - children = gtk_container_get_children (GTK_CONTAINER (widget)); - - for (l = children; l; l = l->next) - { - label = find_menu_label (l->data); - if (label) - break; - } - - g_list_free (children); - } - - return label; -} - -static const gchar * -get_menu_label_text (GtkWidget *menu_item, - GtkWidget **label) -{ - *label = find_menu_label (menu_item); - if (!*label) - return NULL; - - return gtk_label_get_text (GTK_LABEL (*label)); -} - -static gboolean -accel_find_func (GtkAccelKey *key, - GClosure *closure, - gpointer data) -{ - return (GClosure *) data == closure; -} - - -/* - * CarbonMenu functions - */ - -typedef struct -{ - MenuRef menu; -} CarbonMenu; - -static GQuark carbon_menu_quark = 0; - -static CarbonMenu * -carbon_menu_new (void) -{ - return g_slice_new0 (CarbonMenu); -} - -static void -carbon_menu_free (CarbonMenu *menu) -{ - g_slice_free (CarbonMenu, menu); -} - -static CarbonMenu * -carbon_menu_get (GtkWidget *widget) -{ - return g_object_get_qdata (G_OBJECT (widget), carbon_menu_quark); -} - -static void -carbon_menu_connect (GtkWidget *menu, - MenuRef menuRef) -{ - CarbonMenu *carbon_menu = carbon_menu_get (menu); - - if (!carbon_menu) - { - carbon_menu = carbon_menu_new (); - - g_object_set_qdata_full (G_OBJECT (menu), carbon_menu_quark, - carbon_menu, - (GDestroyNotify) carbon_menu_free); - } - - carbon_menu->menu = menuRef; -} - - -/* - * CarbonMenuItem functions - */ - -typedef struct -{ - MenuRef menu; - MenuItemIndex index; - MenuRef submenu; - GClosure *accel_closure; -} CarbonMenuItem; - -static GQuark carbon_menu_item_quark = 0; - -static CarbonMenuItem * -carbon_menu_item_new (void) -{ - return g_slice_new0 (CarbonMenuItem); -} - -static void -carbon_menu_item_free (CarbonMenuItem *menu_item) -{ - if (menu_item->accel_closure) - g_closure_unref (menu_item->accel_closure); - - g_slice_free (CarbonMenuItem, menu_item); -} - -static CarbonMenuItem * -carbon_menu_item_get (GtkWidget *widget) -{ - return g_object_get_qdata (G_OBJECT (widget), carbon_menu_item_quark); -} - -static void -carbon_menu_item_update_state (CarbonMenuItem *carbon_item, - GtkWidget *widget) -{ - gboolean sensitive; - gboolean visible; - UInt32 set_attrs = 0; - UInt32 clear_attrs = 0; - - g_object_get (widget, - "sensitive", &sensitive, - "visible", &visible, - NULL); - - if (!sensitive) - set_attrs |= kMenuItemAttrDisabled; - else - clear_attrs |= kMenuItemAttrDisabled; - - if (!visible) - set_attrs |= kMenuItemAttrHidden; - else - clear_attrs |= kMenuItemAttrHidden; - - ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index, - set_attrs, clear_attrs); -} - -static void -carbon_menu_item_update_active (CarbonMenuItem *carbon_item, - GtkWidget *widget) -{ - gboolean active; - - g_object_get (widget, - "active", &active, - NULL); - - CheckMenuItem (carbon_item->menu, carbon_item->index, - active); -} - -static void -carbon_menu_item_update_submenu (CarbonMenuItem *carbon_item, - GtkWidget *widget) -{ - GtkWidget *submenu; - - submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)); - - if (submenu) - { - GtkWidget *label = NULL; - const gchar *label_text; - CFStringRef cfstr = NULL; - - label_text = get_menu_label_text (widget, &label); - if (label_text) - cfstr = CFStringCreateWithCString (NULL, label_text, - kCFStringEncodingUTF8); - - CreateNewMenu (0, 0, &carbon_item->submenu); - SetMenuTitleWithCFString (carbon_item->submenu, cfstr); - SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index, - carbon_item->submenu); - - sync_menu_shell (GTK_MENU_SHELL (submenu), carbon_item->submenu, FALSE); - - if (cfstr) - CFRelease (cfstr); - } - else - { - SetMenuItemHierarchicalMenu (carbon_item->menu, carbon_item->index, - NULL); - carbon_item->submenu = NULL; - } -} - -static void -carbon_menu_item_update_label (CarbonMenuItem *carbon_item, - GtkWidget *widget) -{ - GtkWidget *label; - const gchar *label_text; - CFStringRef cfstr = NULL; - - label_text = get_menu_label_text (widget, &label); - if (label_text) - cfstr = CFStringCreateWithCString (NULL, label_text, - kCFStringEncodingUTF8); - - SetMenuItemTextWithCFString (carbon_item->menu, carbon_item->index, - cfstr); - - if (cfstr) - CFRelease (cfstr); -} - -static void -carbon_menu_item_update_accelerator (CarbonMenuItem *carbon_item, - GtkWidget *widget) -{ - GtkWidget *label; - - get_menu_label_text (widget, &label); - - if (GTK_IS_ACCEL_LABEL (label) && - GTK_ACCEL_LABEL (label)->accel_closure) - { - GtkAccelKey *key; - - key = gtk_accel_group_find (GTK_ACCEL_LABEL (label)->accel_group, - accel_find_func, - GTK_ACCEL_LABEL (label)->accel_closure); - - if (key && - key->accel_key && - key->accel_flags & GTK_ACCEL_VISIBLE) - { - GdkDisplay *display = gtk_widget_get_display (widget); - GdkKeymap *keymap = gdk_keymap_get_for_display (display); - GdkKeymapKey *keys; - gint n_keys; - - if (gdk_keymap_get_entries_for_keyval (keymap, key->accel_key, - &keys, &n_keys)) - { - UInt8 modifiers = 0; - - SetMenuItemCommandKey (carbon_item->menu, carbon_item->index, - true, keys[0].keycode); - - g_free (keys); - - if (key->accel_mods) - { - if (key->accel_mods & GDK_SHIFT_MASK) - modifiers |= kMenuShiftModifier; - - if (key->accel_mods & GDK_MOD1_MASK) - modifiers |= kMenuOptionModifier; - } - - if (!(key->accel_mods & GDK_CONTROL_MASK)) - { - modifiers |= kMenuNoCommandModifier; - } - - SetMenuItemModifiers (carbon_item->menu, carbon_item->index, - modifiers); - - return; - } - } - } - - /* otherwise, clear the menu shortcut */ - SetMenuItemModifiers (carbon_item->menu, carbon_item->index, - kMenuNoModifiers | kMenuNoCommandModifier); - ChangeMenuItemAttributes (carbon_item->menu, carbon_item->index, - 0, kMenuItemAttrUseVirtualKey); - SetMenuItemCommandKey (carbon_item->menu, carbon_item->index, - false, 0); -} - -static void -carbon_menu_item_accel_changed (GtkAccelGroup *accel_group, - guint keyval, - GdkModifierType modifier, - GClosure *accel_closure, - GtkWidget *widget) -{ - CarbonMenuItem *carbon_item = carbon_menu_item_get (widget); - GtkWidget *label; - - get_menu_label_text (widget, &label); - - if (GTK_IS_ACCEL_LABEL (label) && - GTK_ACCEL_LABEL (label)->accel_closure == accel_closure) - carbon_menu_item_update_accelerator (carbon_item, widget); -} - -static void -carbon_menu_item_update_accel_closure (CarbonMenuItem *carbon_item, - GtkWidget *widget) -{ - GtkAccelGroup *group; - GtkWidget *label; - - get_menu_label_text (widget, &label); - - if (carbon_item->accel_closure) - { - group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure); - - g_signal_handlers_disconnect_by_func (group, - carbon_menu_item_accel_changed, - widget); - - g_closure_unref (carbon_item->accel_closure); - carbon_item->accel_closure = NULL; - } - - if (GTK_IS_ACCEL_LABEL (label)) - carbon_item->accel_closure = GTK_ACCEL_LABEL (label)->accel_closure; - - if (carbon_item->accel_closure) - { - g_closure_ref (carbon_item->accel_closure); - - group = gtk_accel_group_from_accel_closure (carbon_item->accel_closure); - - g_signal_connect_object (group, "accel-changed", - G_CALLBACK (carbon_menu_item_accel_changed), - widget, 0); - } - - carbon_menu_item_update_accelerator (carbon_item, widget); -} - -static void -carbon_menu_item_notify (GObject *object, - GParamSpec *pspec, - CarbonMenuItem *carbon_item) -{ - if (!strcmp (pspec->name, "sensitive") || - !strcmp (pspec->name, "visible")) - { - carbon_menu_item_update_state (carbon_item, GTK_WIDGET (object)); - } - else if (!strcmp (pspec->name, "active")) - { - carbon_menu_item_update_active (carbon_item, GTK_WIDGET (object)); - } - else if (!strcmp (pspec->name, "submenu")) - { - carbon_menu_item_update_submenu (carbon_item, GTK_WIDGET (object)); - } -} - -static void -carbon_menu_item_notify_label (GObject *object, - GParamSpec *pspec, - gpointer data) -{ - CarbonMenuItem *carbon_item = carbon_menu_item_get (GTK_WIDGET (object)); - - if (!strcmp (pspec->name, "label")) - { - carbon_menu_item_update_label (carbon_item, - GTK_WIDGET (object)); - } - else if (!strcmp (pspec->name, "accel-closure")) - { - carbon_menu_item_update_accel_closure (carbon_item, - GTK_WIDGET (object)); - } -} - -static CarbonMenuItem * -carbon_menu_item_connect (GtkWidget *menu_item, - GtkWidget *label, - MenuRef menu, - MenuItemIndex index) -{ - CarbonMenuItem *carbon_item = carbon_menu_item_get (menu_item); - - if (!carbon_item) - { - carbon_item = carbon_menu_item_new (); - - g_object_set_qdata_full (G_OBJECT (menu_item), carbon_menu_item_quark, - carbon_item, - (GDestroyNotify) carbon_menu_item_free); - - g_signal_connect (menu_item, "notify", - G_CALLBACK (carbon_menu_item_notify), - carbon_item); - - if (label) - g_signal_connect_swapped (label, "notify::label", - G_CALLBACK (carbon_menu_item_notify_label), - menu_item); - } - - carbon_item->menu = menu; - carbon_item->index = index; - - return carbon_item; -} - - -/* - * carbon event handler - */ - -static OSStatus -menu_event_handler_func (EventHandlerCallRef event_handler_call_ref, - EventRef event_ref, - void *data) -{ - UInt32 event_class = GetEventClass (event_ref); - UInt32 event_kind = GetEventKind (event_ref); - MenuRef menu_ref; - - switch (event_class) - { - case kEventClassCommand: - /* This is called when activating (is that the right GTK+ term?) - * a menu item. - */ - if (event_kind == kEventCommandProcess) - { - HICommand command; - OSStatus err; - - //g_print ("Menu: kEventClassCommand/kEventCommandProcess\n"); - - err = GetEventParameter (event_ref, kEventParamDirectObject, - typeHICommand, 0, - sizeof (command), 0, &command); - - if (err == noErr) - { - GtkWidget *widget = NULL; - - if (command.commandID == kHICommandQuit) - { - gtk_main_quit (); /* Just testing... */ - return noErr; - } - - /* Get any GtkWidget associated with the item. */ - err = GetMenuItemProperty (command.menu.menuRef, - command.menu.menuItemIndex, - GTK_QUARTZ_MENU_CREATOR, - GTK_QUARTZ_ITEM_WIDGET, - sizeof (widget), 0, &widget); - if (err == noErr && widget) - { - gtk_menu_item_activate (GTK_MENU_ITEM (widget)); - return noErr; - } - } - } - break; - - case kEventClassMenu: - GetEventParameter (event_ref, - kEventParamDirectObject, - typeMenuRef, - NULL, - sizeof (menu_ref), - NULL, - &menu_ref); - - switch (event_kind) - { - case kEventMenuTargetItem: - /* This is called when an item is selected (what is the - * GTK+ term? prelight?) - */ - //g_print ("kEventClassMenu/kEventMenuTargetItem\n"); - break; - - case kEventMenuOpening: - /* Is it possible to dynamically build the menu here? We - * can at least set visibility/sensitivity. - */ - //g_print ("kEventClassMenu/kEventMenuOpening\n"); - break; - - case kEventMenuClosed: - //g_print ("kEventClassMenu/kEventMenuClosed\n"); - break; - - default: - break; - } - - break; - - default: - break; - } - - return CallNextEventHandler (event_handler_call_ref, event_ref); -} - -static void -setup_menu_event_handler (void) -{ - EventHandlerUPP menu_event_handler_upp; - EventHandlerRef menu_event_handler_ref; - const EventTypeSpec menu_events[] = { - { kEventClassCommand, kEventCommandProcess }, - { kEventClassMenu, kEventMenuTargetItem }, - { kEventClassMenu, kEventMenuOpening }, - { kEventClassMenu, kEventMenuClosed } - }; - - /* FIXME: We might have to install one per window? */ - - menu_event_handler_upp = NewEventHandlerUPP (menu_event_handler_func); - InstallEventHandler (GetApplicationEventTarget (), menu_event_handler_upp, - GetEventTypeCount (menu_events), menu_events, 0, - &menu_event_handler_ref); - -#if 0 - /* FIXME: Remove the handler with: */ - RemoveEventHandler(menu_event_handler_ref); - DisposeEventHandlerUPP(menu_event_handler_upp); -#endif -} - -static void -sync_menu_shell (GtkMenuShell *menu_shell, - MenuRef carbon_menu, - gboolean toplevel) -{ - GList *children; - GList *l; - MenuItemIndex carbon_index = 1; - - carbon_menu_connect (GTK_WIDGET (menu_shell), carbon_menu); - - children = gtk_container_get_children (GTK_CONTAINER (menu_shell)); - - for (l = children; l; l = l->next) - { - GtkWidget *menu_item = l->data; - CarbonMenuItem *carbon_item; - - if (GTK_IS_TEAROFF_MENU_ITEM (menu_item)) - continue; - - if (toplevel && g_object_get_data (G_OBJECT (menu_item), "gtk-empty-menu-item")) - continue; - - carbon_item = carbon_menu_item_get (menu_item); - - if (carbon_item && carbon_item->index != carbon_index) - { - DeleteMenuItem (carbon_item->menu, - carbon_item->index); - carbon_item = NULL; - } - - if (!carbon_item) - { - GtkWidget *label = NULL; - const gchar *label_text; - CFStringRef cfstr = NULL; - MenuItemAttributes attributes = 0; - - label_text = get_menu_label_text (menu_item, &label); - if (label_text) - cfstr = CFStringCreateWithCString (NULL, label_text, - kCFStringEncodingUTF8); - - if (GTK_IS_SEPARATOR_MENU_ITEM (menu_item)) - attributes |= kMenuItemAttrSeparator; - - if (!GTK_WIDGET_IS_SENSITIVE (menu_item)) - attributes |= kMenuItemAttrDisabled; - - if (!GTK_WIDGET_VISIBLE (menu_item)) - attributes |= kMenuItemAttrHidden; - - InsertMenuItemTextWithCFString (carbon_menu, cfstr, - carbon_index, - attributes, 0); - SetMenuItemProperty (carbon_menu, carbon_index, - GTK_QUARTZ_MENU_CREATOR, - GTK_QUARTZ_ITEM_WIDGET, - sizeof (menu_item), &menu_item); - - if (cfstr) - CFRelease (cfstr); - - carbon_item = carbon_menu_item_connect (menu_item, label, - carbon_menu, - carbon_index); - - if (GTK_IS_CHECK_MENU_ITEM (menu_item)) - carbon_menu_item_update_active (carbon_item, menu_item); - - carbon_menu_item_update_accel_closure (carbon_item, menu_item); - - if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item))) - carbon_menu_item_update_submenu (carbon_item, menu_item); - } - - carbon_index++; - } - - g_list_free (children); -} - -void -sync_menu_takeover_menu (GtkMenuShell *menu_shell) -{ - MenuRef carbon_menubar; - - g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); - - if (carbon_menu_quark == 0) - carbon_menu_quark = g_quark_from_static_string ("CarbonMenu"); - - if (carbon_menu_item_quark == 0) - carbon_menu_item_quark = g_quark_from_static_string ("CarbonMenuItem"); - - CreateNewMenu (0 /*id*/, 0 /*options*/, &carbon_menubar); - SetRootMenu (carbon_menubar); - - setup_menu_event_handler (); - - sync_menu_shell (menu_shell, carbon_menubar, TRUE); -} - -#else - -void -sync_menu_takeover_menu (GtkMenuShell *menu_shell) -{ - -} - -#endif diff --git a/src/audacious/sync-menu.h b/src/audacious/sync-menu.h deleted file mode 100644 index 0715a31..0000000 --- a/src/audacious/sync-menu.h +++ /dev/null @@ -1,27 +0,0 @@ -/* GTK+ Integration for the Mac OS X Menubar. - * - * Copyright (C) 2007 Pioneer Research Center USA, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -void sync_menu_takeover_menu (GtkMenuShell *menu_shell); - -G_END_DECLS diff --git a/src/audacious/ui_albumart.c b/src/audacious/ui_albumart.c index 4bc38be..940ceed 100644 --- a/src/audacious/ui_albumart.c +++ b/src/audacious/ui_albumart.c @@ -28,9 +28,7 @@ #include <gtk/gtk.h> #include <string.h> -#include "ui_fileinfopopup.h" -#include "main.h" -#include "playback.h" +#include "audconfig.h" static gboolean has_front_cover_extension(const gchar *name) @@ -117,9 +115,8 @@ is_file_image(const gchar *imgfile, const gchar *file_name) } } -gchar* -fileinfo_recursive_get_image(const gchar* path, - const gchar* file_name, gint depth) +static gchar * fileinfo_recursive_get_image (const gchar * path, const gchar * + file_name, gint depth) { GDir *d; @@ -191,3 +188,14 @@ fileinfo_recursive_get_image(const gchar* path, return NULL; } + +gchar * get_associated_image_file (const gchar * filename) +{ + gchar * path = g_path_get_dirname (filename); + gchar * base = g_path_get_basename (filename); + gchar * image_file = fileinfo_recursive_get_image (path, base, 0); + + g_free (path); + g_free (base); + return image_file; +} diff --git a/src/audacious/ui_albumart.h b/src/audacious/ui_albumart.h new file mode 100644 index 0000000..8775128 --- /dev/null +++ b/src/audacious/ui_albumart.h @@ -0,0 +1,8 @@ +/* + * TEMPORARY. + * + * Album art needs to be reworked. It should be read from file tags and stored + * in tuples. -jlindgren + */ + +gchar * get_associated_image_file (const gchar * filename); diff --git a/src/audacious/ui_fileinfo.c b/src/audacious/ui_fileinfo.c deleted file mode 100644 index 7c256ad..0000000 --- a/src/audacious/ui_fileinfo.c +++ /dev/null @@ -1,993 +0,0 @@ -/* - * Audacious: A cross-platform multimedia player - * Copyright (c) 2006 William Pitcock, Tony Vroon, George Averill, - * Giacomo Lozito, Derek Pomery and Yoshiki Yazawa. - * Copyright (c) 2008 Eugene Zagidullin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses>. - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <gdk/gdkkeysyms.h> -#include <glib.h> -#include <glib/gi18n.h> -#include <gtk/gtk.h> -#include <string.h> -#include <stddef.h> -#include <stdio.h> -#include <stdarg.h> -#include <sys/types.h> -#include <dirent.h> -#include <unistd.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include "plugin.h" -#include "pluginenum.h" -#include "effect.h" -#include "audstrings.h" -#include "general.h" -#include "output.h" -#include "playlist-new.h" -#include "probe.h" -#include "visualization.h" - -#include "main.h" -#include "util.h" -#include "tuple.h" -#include "vfs.h" - -#include "build_stamp.h" -#include "ui_fileinfo.h" - -#define G_FREE_CLEAR(a) if(a != NULL) { g_free(a); a = NULL; } -#define STATUS_TIMEOUT 3*1000 - -GtkWidget *fileinfo_win = NULL; - -GtkWidget *entry_location; -GtkWidget *entry_title; -GtkWidget *entry_artist; -GtkWidget *entry_album; -GtkWidget *entry_comment; -GtkWidget *entry_year; -GtkWidget *entry_track; -GtkWidget *entry_genre; - -GtkWidget *image_artwork; - -GtkWidget *image_fileicon; -GtkWidget *label_format_name; -GtkWidget *label_quality; -GtkWidget *label_bitrate; -GtkWidget *btn_apply; -GtkWidget *label_mini_status; -GtkWidget *arrow_rawdata; -GtkWidget *treeview_rawdata; - -enum { - RAWDATA_KEY, - RAWDATA_VALUE, - RAWDATA_N_COLS -}; - -static gchar *current_file = NULL; -static InputPlugin *current_ip = NULL; -static gboolean something_changed = FALSE; - -/* stolen from Audacious 1.4 vorbis plugin. --nenolod */ -static const gchar *genre_table[] = { - N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"), - N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"), - N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"), - N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"), - N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"), - N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"), - N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"), - N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"), - N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"), - N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("AlternRock"), - N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"), - N_("Meditative"), N_("Instrumental Pop"), - N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"), - N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"), - N_("Pop-Folk"), N_("Eurodance"), N_("Dream"), - N_("Southern Rock"), N_("Comedy"), N_("Cult"), - N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"), - N_("Pop/Funk"), N_("Jungle"), N_("Native American"), - N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"), - N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"), - N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"), - N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"), - N_("Folk/Rock"), N_("National Folk"), N_("Swing"), - N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"), - N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"), - N_("Gothic Rock"), N_("Progressive Rock"), - N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"), - N_("Big Band"), N_("Chorus"), N_("Easy Listening"), - N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"), - N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"), - N_("Booty Bass"), N_("Primus"), N_("Porn Groove"), - N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"), - N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"), - N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"), - N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"), - N_("Euro-House"), N_("Dance Hall"), N_("Goa"), - N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"), - N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"), - N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"), - N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"), - N_("Contemporary Christian"), N_("Christian Rock"), - N_("Merengue"), N_("Salsa"), N_("Thrash Metal"), - N_("Anime"), N_("JPop"), N_("Synthpop") -}; - -static GList *genre_list = NULL; - -static void -fileinfo_entry_set_text(GtkWidget *widget, const char *text) -{ - if (widget == NULL) - return; - - gtk_entry_set_text(GTK_ENTRY(widget), text != NULL ? text : ""); -} - -static void -set_entry_str_from_field(GtkWidget *widget, Tuple *tuple, gint fieldn, gboolean editable) -{ - gchar *text; - - if(widget != NULL) { - text = (gchar*)tuple_get_string(tuple, fieldn, NULL); - gtk_entry_set_text(GTK_ENTRY(widget), text != NULL ? text : ""); - gtk_editable_set_editable(GTK_EDITABLE(widget), editable); - } -} - -static void -set_entry_int_from_field(GtkWidget *widget, Tuple *tuple, gint fieldn, gboolean editable) -{ - gchar *text; - - if(widget == NULL) return; - - if(tuple_get_value_type(tuple, fieldn, NULL) == TUPLE_INT) { - text = g_strdup_printf("%d", tuple_get_int(tuple, fieldn, NULL)); - gtk_entry_set_text(GTK_ENTRY(widget), text); - gtk_editable_set_editable(GTK_EDITABLE(widget), editable); - g_free(text); - } else { - gtk_entry_set_text(GTK_ENTRY(widget), ""); - gtk_editable_set_editable(GTK_EDITABLE(widget), editable); - } -} - -static void -set_field_str_from_entry(Tuple *tuple, gint fieldn, GtkWidget *widget) -{ - if(widget == NULL) return; - tuple_associate_string(tuple, fieldn, NULL, gtk_entry_get_text(GTK_ENTRY(widget))); -} - -static void -set_field_int_from_entry(Tuple *tuple, gint fieldn, GtkWidget *widget) -{ - gchar *tmp; - if(widget == NULL) return; - - tmp = (gchar*)gtk_entry_get_text(GTK_ENTRY(widget)); - if(*tmp != '\0') - tuple_associate_int(tuple, fieldn, NULL, atoi(tmp)); - else - tuple_associate_int(tuple, fieldn, NULL, -1); -} - -static void -fileinfo_label_set_text(GtkWidget *widget, const char *text) -{ - gchar *tmp; - - if (widget == NULL) - return; - - if (text) { - tmp = g_strdup_printf("<span size=\"small\">%s</span>", text); - gtk_label_set_text(GTK_LABEL(widget), tmp); - gtk_label_set_use_markup(GTK_LABEL(widget), TRUE); - g_free(tmp); - } else { - gtk_label_set_text(GTK_LABEL(widget), _("<span size=\"small\">n/a</span>")); - gtk_label_set_use_markup(GTK_LABEL(widget), TRUE); - } -} - -static void -fileinfo_entry_set_image(GtkWidget *widget, const char *text) -{ - GdkPixbuf *pixbuf; - int width, height; - double aspect; - GdkPixbuf *pixbuf2; - - if (widget == NULL) - return; - - pixbuf = gdk_pixbuf_new_from_file(text, NULL); - - if (pixbuf == NULL) - return; - - width = gdk_pixbuf_get_width(GDK_PIXBUF(pixbuf)); - height = gdk_pixbuf_get_height(GDK_PIXBUF(pixbuf)); - - if (strcmp(DATA_DIR "/images/audio.png", text)) { - if (width == 0) - width = 1; - aspect = (double)height / (double)width; - - if (aspect > 1.0) { - height = (int)(cfg.filepopup_pixelsize * aspect); - width = cfg.filepopup_pixelsize; - } else { - height = cfg.filepopup_pixelsize; - width = (int)(cfg.filepopup_pixelsize / aspect); - } - - pixbuf2 = gdk_pixbuf_scale_simple(GDK_PIXBUF(pixbuf), width, height, GDK_INTERP_BILINEAR); - g_object_unref(G_OBJECT(pixbuf)); - pixbuf = pixbuf2; - } - - gtk_image_set_from_pixbuf(GTK_IMAGE(widget), GDK_PIXBUF(pixbuf)); - g_object_unref(G_OBJECT(pixbuf)); -} - -static int -fileinfo_hide(gpointer unused) -{ - if(GTK_WIDGET_VISIBLE(fileinfo_win)) gtk_widget_hide(fileinfo_win); - - /* Clear it out. */ - fileinfo_entry_set_text(entry_title, ""); - fileinfo_entry_set_text(entry_artist, ""); - fileinfo_entry_set_text(entry_album, ""); - fileinfo_entry_set_text(entry_comment, ""); - fileinfo_entry_set_text(gtk_bin_get_child(GTK_BIN(entry_genre)), ""); - fileinfo_entry_set_text(entry_year, ""); - fileinfo_entry_set_text(entry_track, ""); - fileinfo_entry_set_text(entry_location, ""); - - fileinfo_label_set_text(label_format_name, NULL); - fileinfo_label_set_text(label_quality, NULL); - fileinfo_label_set_text(label_bitrate, NULL); - - if (label_mini_status != NULL) { - gtk_label_set_text(GTK_LABEL(label_mini_status), "<span size=\"small\"></span>"); - gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE); - } - - something_changed = FALSE; - gtk_widget_set_sensitive(btn_apply, FALSE); - - current_ip = NULL; - G_FREE_CLEAR(current_file); - - fileinfo_entry_set_image(image_artwork, DATA_DIR "/images/audio.png"); - return 1; -} - -static void -entry_changed (GtkEditable *editable, gpointer user_data) -{ - if(current_file != NULL && current_ip != NULL && current_ip->update_song_tuple != NULL) { - something_changed = TRUE; - gtk_widget_set_sensitive(btn_apply, TRUE); - } -} - -static gboolean -ministatus_timeout_proc (gpointer data) -{ - GtkLabel *status = GTK_LABEL(data); - gtk_label_set_text(status, "<span size=\"small\"></span>"); - gtk_label_set_use_markup(status, TRUE); - - return FALSE; -} - -static void -ministatus_display_message(gchar *text) -{ - if(label_mini_status != NULL) { - gchar *tmp = g_strdup_printf("<span size=\"small\">%s</span>", text); - gtk_label_set_text(GTK_LABEL(label_mini_status), tmp); - g_free(tmp); - gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE); - g_timeout_add (STATUS_TIMEOUT, (GSourceFunc) ministatus_timeout_proc, (gpointer) label_mini_status); - } -} - -static void -message_update_successfull() -{ - ministatus_display_message(_("Metadata updated successfully")); -} - -static void -message_update_failed() -{ - ministatus_display_message(_("Metadata updating failed")); -} - -static void -fileinfo_update_tuple(gpointer data) -{ - Tuple *tuple; - VFSFile *fd; - - if (current_file != NULL && current_ip != NULL && current_ip->update_song_tuple != NULL && something_changed) { - tuple = tuple_new(); - fd = vfs_fopen(current_file, "r+b"); - - if (fd != NULL) { - set_field_str_from_entry(tuple, FIELD_TITLE, entry_title); - set_field_str_from_entry(tuple, FIELD_ARTIST, entry_artist); - set_field_str_from_entry(tuple, FIELD_ALBUM, entry_album); - set_field_str_from_entry(tuple, FIELD_COMMENT, entry_comment); - set_field_str_from_entry(tuple, FIELD_GENRE, gtk_bin_get_child(GTK_BIN(entry_genre))); - - set_field_int_from_entry(tuple, FIELD_YEAR, entry_year); - set_field_int_from_entry(tuple, FIELD_TRACK_NUMBER, entry_track); - - plugin_set_current((Plugin *)current_ip); - if (current_ip->update_song_tuple(tuple, fd)) { - message_update_successfull(); - something_changed = FALSE; - gtk_widget_set_sensitive(btn_apply, FALSE); - } else - message_update_failed(); - - vfs_fclose(fd); - - } else - message_update_failed(); - - mowgli_object_unref(tuple); - } -} - -/** - * Looks up an icon from a NULL-terminated list of icon names. - * - * size: the requested size - * name: the default name - * ... : a NULL-terminated list of alternates - */ -GdkPixbuf * -themed_icon_lookup(gint size, const gchar *name, ...) -{ - GtkIconTheme *icon_theme; - GdkPixbuf *pixbuf; - GError *error = NULL; - gchar *n; - va_list par; - - icon_theme = gtk_icon_theme_get_default (); - pixbuf = gtk_icon_theme_load_icon (icon_theme, name, size, 0, &error); - - if (pixbuf != NULL) - return pixbuf; - - if (error != NULL) - g_error_free(error); - - /* fallback */ - va_start(par, name); - while((n = (gchar*)va_arg(par, gchar *)) != NULL) { - error = NULL; - pixbuf = gtk_icon_theme_load_icon (icon_theme, n, size, 0, &error); - - if (pixbuf) { - va_end(par); - return pixbuf; - } - - if (error != NULL) - g_error_free(error); - } - - return NULL; -} - -/** - * Intelligently looks up an icon for a mimetype. Supports - * HIDEOUSLY BROKEN gnome icon naming scheme too. - * - * size : the requested size - * mime_type: the mime type. - */ -GdkPixbuf * -mime_icon_lookup(gint size, const gchar *mime_type) /* smart icon resolving routine :) */ -{ - gchar *mime_as_is; /* audio-x-mp3 */ - gchar *mime_gnome; /* gnome-mime-audio-x-mp3 */ - gchar *mime_generic; /* audio-x-generic */ - gchar *mime_gnome_generic; /* gnome-mime-audio */ - - GdkPixbuf *icon = NULL; - - gchar **s = g_strsplit(mime_type, "/", 2); - if(s[1] != NULL) { - mime_as_is = g_strdup_printf("%s-%s", s[0], s[1]); - mime_gnome = g_strdup_printf("gnome-mime-%s-%s", s[0], s[1]); - mime_generic = g_strdup_printf("%s-x-generic", s[0]); - mime_gnome_generic = g_strdup_printf("gnome-mime-%s", s[0]); - icon = themed_icon_lookup(size, mime_as_is, mime_gnome, mime_generic, mime_gnome_generic, s[0], NULL); /* s[0] is category */ - g_free(mime_gnome_generic); - g_free(mime_generic); - g_free(mime_gnome); - g_free(mime_as_is); - } - g_strfreev(s); - - return icon; -} - -static gboolean fileinfo_keypress (GtkWidget * widget, GdkEventKey * event, - void * unused) -{ - if (event->keyval == GDK_Escape) - { - fileinfo_hide (NULL); - return TRUE; - } - - return FALSE; -} - -void -create_fileinfo_window(void) -{ - GtkWidget *hbox; - GtkWidget *hbox_status_and_bbox; - GtkWidget *vbox0; - GtkWidget *vbox1; - GtkWidget *vbox2; - GtkWidget *vbox3; - GtkWidget *label_title; - GtkWidget *label_artist; - GtkWidget *label_album; - GtkWidget *label_comment; - GtkWidget *label_genre; - GtkWidget *label_year; - GtkWidget *label_track; - GtkWidget *label_location; - GtkWidget *label_general; - GtkWidget *label_format; - GtkWidget *label_quality_label; - GtkWidget *label_bitrate_label; - GtkWidget *codec_hbox; - GtkWidget *codec_table; - GtkWidget *table1; - GtkWidget *bbox_close; - GtkWidget *btn_close; - GtkWidget *alignment; - GtkWidget *separator; - GtkWidget *scrolledwindow; - GtkTreeViewColumn *column; - GtkCellRenderer *renderer; - gint i; - - fileinfo_win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_container_set_border_width(GTK_CONTAINER(fileinfo_win), 6); - gtk_window_set_title(GTK_WINDOW(fileinfo_win), _("Track Information")); - gtk_window_set_position(GTK_WINDOW(fileinfo_win), GTK_WIN_POS_CENTER); - gtk_window_set_type_hint(GTK_WINDOW(fileinfo_win), GDK_WINDOW_TYPE_HINT_DIALOG); - - vbox0 = gtk_vbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(fileinfo_win), vbox0); - - hbox = gtk_hbox_new(FALSE, 6); - gtk_box_pack_start(GTK_BOX(vbox0), hbox, TRUE, TRUE, 0); - - image_artwork = gtk_image_new(); - gtk_box_pack_start(GTK_BOX(hbox), image_artwork, FALSE, FALSE, 0); - gtk_misc_set_alignment(GTK_MISC(image_artwork), 0.5, 0); - gtk_image_set_from_file(GTK_IMAGE(image_artwork), DATA_DIR "/images/audio.png"); - separator = gtk_vseparator_new(); - gtk_box_pack_start(GTK_BOX(hbox), separator, FALSE, FALSE, 0); - - vbox1 = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), vbox1, TRUE, TRUE, 0); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox1), alignment, TRUE, TRUE, 0); - - vbox2 = gtk_vbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(alignment), vbox2); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox1), alignment, TRUE, TRUE, 0); - - vbox3 = gtk_vbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(alignment), vbox3); - - label_general = gtk_label_new(_("<span size=\"small\">General</span>")); - gtk_box_pack_start (GTK_BOX (vbox2), label_general, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_general), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_general), 0, 0.5); - - alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 0, 0); - gtk_box_pack_start (GTK_BOX (vbox2), alignment, FALSE, FALSE, 0); - - codec_hbox = gtk_hbox_new(FALSE, 6); - gtk_container_add (GTK_CONTAINER(alignment), codec_hbox); - - image_fileicon = gtk_image_new_from_stock (GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG); - gtk_box_pack_start (GTK_BOX (codec_hbox), image_fileicon, FALSE, FALSE, 0); - - codec_table = gtk_table_new(3, 2, FALSE); - gtk_table_set_row_spacings (GTK_TABLE(codec_table), 6); - gtk_table_set_col_spacings (GTK_TABLE(codec_table), 12); - gtk_box_pack_start (GTK_BOX (codec_hbox), codec_table, FALSE, FALSE, 0); - - label_format = gtk_label_new(_("<span size=\"small\">Format:</span>")); - gtk_label_set_use_markup(GTK_LABEL(label_format), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_format), 0, 0.5); - label_quality_label = gtk_label_new(_("<span size=\"small\">Quality:</span>")); - gtk_label_set_use_markup(GTK_LABEL(label_quality_label), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_quality_label), 0, 0.5); - label_bitrate_label = gtk_label_new(_("<span size=\"small\">Bitrate:</span>")); - gtk_label_set_use_markup(GTK_LABEL(label_bitrate_label), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_bitrate_label), 0, 0.5); - - label_format_name = gtk_label_new(_("<span size=\"small\">n/a</span>")); - gtk_label_set_use_markup(GTK_LABEL(label_format_name), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_format_name), 0, 0.5); - label_quality = gtk_label_new(_("<span size=\"small\">n/a</span>")); - gtk_label_set_use_markup(GTK_LABEL(label_quality), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_quality), 0, 0.5); - label_bitrate = gtk_label_new(_("<span size=\"small\">n/a</span>")); - gtk_label_set_use_markup(GTK_LABEL(label_bitrate), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_bitrate), 0, 0.5); - - gtk_table_attach(GTK_TABLE(codec_table), label_format, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_table_attach(GTK_TABLE(codec_table), label_format_name, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_table_attach(GTK_TABLE(codec_table), label_quality_label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_table_attach(GTK_TABLE(codec_table), label_quality, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_table_attach(GTK_TABLE(codec_table), label_bitrate_label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_table_attach(GTK_TABLE(codec_table), label_bitrate, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - - label_title = gtk_label_new(_("<span size=\"small\">Title</span>")); - gtk_box_pack_start(GTK_BOX(vbox2), label_title, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_title), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_title), 0, 0); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); - entry_title = gtk_entry_new(); - gtk_container_add(GTK_CONTAINER(alignment), entry_title); - g_signal_connect(G_OBJECT(entry_title), "changed", (GCallback) entry_changed, NULL); - - label_artist = gtk_label_new(_("<span size=\"small\">Artist</span>")); - gtk_box_pack_start(GTK_BOX(vbox2), label_artist, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_artist), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_artist), 0, 0.5); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); - entry_artist = gtk_entry_new(); - gtk_container_add(GTK_CONTAINER(alignment), entry_artist); - g_signal_connect(G_OBJECT(entry_artist), "changed", (GCallback) entry_changed, NULL); - - label_album = gtk_label_new(_("<span size=\"small\">Album</span>")); - gtk_box_pack_start(GTK_BOX(vbox2), label_album, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_album), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_album), 0, 0.5); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); - entry_album = gtk_entry_new(); - gtk_container_add(GTK_CONTAINER(alignment), entry_album); - g_signal_connect(G_OBJECT(entry_album), "changed", (GCallback) entry_changed, NULL); - - label_comment = gtk_label_new(_("<span size=\"small\">Comment</span>")); - gtk_box_pack_start(GTK_BOX(vbox2), label_comment, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_comment), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_comment), 0, 0.5); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); - entry_comment = gtk_entry_new(); - gtk_container_add (GTK_CONTAINER(alignment), entry_comment); - g_signal_connect(G_OBJECT(entry_comment), "changed", (GCallback) entry_changed, NULL); - - label_genre = gtk_label_new(_("<span size=\"small\">Genre</span>")); - gtk_box_pack_start(GTK_BOX(vbox2), label_genre, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_genre), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_genre), 0, 0.5); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); - entry_genre = gtk_combo_box_entry_new_text(); - - if (!genre_list) { - GList *iter; - - for (i = 0; i < G_N_ELEMENTS(genre_table); i++) - genre_list = g_list_prepend(genre_list, _(genre_table[i])); - genre_list = g_list_sort(genre_list, (GCompareFunc) g_utf8_collate); - - MOWGLI_ITER_FOREACH(iter, genre_list) - gtk_combo_box_append_text(GTK_COMBO_BOX(entry_genre), iter->data); - } - - gtk_container_add(GTK_CONTAINER(alignment), entry_genre); - g_signal_connect(G_OBJECT(entry_genre), "changed", (GCallback) entry_changed, NULL); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_box_pack_start(GTK_BOX(vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 6, 0, 0); - table1 = gtk_table_new(2, 2, FALSE); - gtk_container_add(GTK_CONTAINER(alignment), table1); - gtk_table_set_col_spacings(GTK_TABLE(table1), 6); - - label_year = gtk_label_new(_("<span size=\"small\">Year</span>")); - gtk_table_attach(GTK_TABLE(table1), label_year, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_label_set_use_markup(GTK_LABEL(label_year), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_year), 0, 0.5); - - entry_year = gtk_entry_new(); - gtk_table_attach(GTK_TABLE(table1), entry_year, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - g_signal_connect(G_OBJECT(entry_year), "changed", (GCallback) entry_changed, NULL); - - label_track = gtk_label_new(_("<span size=\"small\">Track Number</span>")); - gtk_table_attach(GTK_TABLE(table1), label_track, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - gtk_label_set_use_markup(GTK_LABEL(label_track), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_track), 0, 0.5); - - entry_track = gtk_entry_new(); - gtk_table_attach(GTK_TABLE(table1), entry_track, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (0), 0, 0); - g_signal_connect(G_OBJECT(entry_track), "changed", (GCallback) entry_changed, NULL); - - label_location = gtk_label_new(_("<span size=\"small\">Location</span>")); - gtk_box_pack_start(GTK_BOX(vbox2), label_location, FALSE, FALSE, 0); - gtk_label_set_use_markup(GTK_LABEL(label_location), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_location), 0, 0.5); - - alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_box_pack_start (GTK_BOX (vbox2), alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 6, 0, 0); - - entry_location = gtk_entry_new(); - gtk_container_add(GTK_CONTAINER(alignment), entry_location); - gtk_editable_set_editable(GTK_EDITABLE(entry_location), FALSE); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - hbox = gtk_hbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(alignment), hbox); - gtk_box_pack_start(GTK_BOX(vbox3), alignment, TRUE, TRUE, 0); - - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 6, 0, 0); - arrow_rawdata = gtk_expander_new(_("<span size=\"small\">Raw Metadata</span>")); - gtk_expander_set_use_markup(GTK_EXPANDER(arrow_rawdata), TRUE); - gtk_container_add(GTK_CONTAINER(alignment), arrow_rawdata); - gtk_box_pack_start(GTK_BOX(hbox), alignment, TRUE, TRUE, 0); - - scrolledwindow = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN); - gtk_container_add(GTK_CONTAINER(arrow_rawdata), scrolledwindow); - - treeview_rawdata = gtk_tree_view_new(); - gtk_container_add(GTK_CONTAINER(scrolledwindow), treeview_rawdata); - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview_rawdata), TRUE); - gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview_rawdata), TRUE); - gtk_widget_set_size_request(treeview_rawdata, -1, 130); - - column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(column, _("Key")); - gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); - gtk_tree_view_column_set_spacing(column, 4); - gtk_tree_view_column_set_resizable(column, FALSE); - gtk_tree_view_column_set_fixed_width(column, 50); - - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer, FALSE); - gtk_tree_view_column_set_attributes(column, renderer, - "text", RAWDATA_KEY, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_rawdata), column); - - column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(column, _("Value")); - gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); - gtk_tree_view_column_set_spacing(column, 4); - gtk_tree_view_column_set_resizable(column, FALSE); - gtk_tree_view_column_set_fixed_width(column, 50); - - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_start(column, renderer, FALSE); - gtk_tree_view_column_set_attributes(column, renderer, - "text", RAWDATA_VALUE, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_rawdata), column); - - hbox_status_and_bbox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start (GTK_BOX (vbox0), hbox_status_and_bbox, FALSE, FALSE, 0); - - label_mini_status = gtk_label_new("<span size=\"small\"></span>"); - gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE); - gtk_misc_set_alignment(GTK_MISC(label_mini_status), 0, 0.5); - gtk_box_pack_start (GTK_BOX (hbox_status_and_bbox), label_mini_status, TRUE, TRUE, 0); - - bbox_close = gtk_hbutton_box_new(); - gtk_box_set_spacing(GTK_BOX(bbox_close), 6); - gtk_box_pack_start(GTK_BOX(hbox_status_and_bbox), bbox_close, FALSE, FALSE, 0); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox_close), GTK_BUTTONBOX_END); - - btn_apply = gtk_button_new_from_stock("gtk-save"); - gtk_container_add(GTK_CONTAINER(bbox_close), btn_apply); - g_signal_connect(G_OBJECT(btn_apply), "clicked", (GCallback) fileinfo_update_tuple, NULL); - gtk_widget_set_sensitive(btn_apply, FALSE); - - btn_close = gtk_button_new_from_stock("gtk-close"); - gtk_container_add(GTK_CONTAINER(bbox_close), btn_close); - GTK_WIDGET_SET_FLAGS(btn_close, GTK_CAN_DEFAULT); - g_signal_connect(G_OBJECT(btn_close), "clicked", (GCallback) fileinfo_hide, NULL); - g_signal_connect ((GObject *) fileinfo_win, "delete-event", (GCallback) - fileinfo_hide, NULL); - g_signal_connect ((GObject *) fileinfo_win, "key-press-event", (GCallback) - fileinfo_keypress, NULL); - - gtk_widget_show_all (vbox0); -} - -static void -fileinfo_show_for_tuple(Tuple *tuple, gboolean updating_enabled) -{ - gchar *tmp = NULL; - GdkPixbuf *icon = NULL; - GtkTreeIter iter; - GtkListStore *store; - mowgli_dictionary_iteration_state_t state; - TupleValue *tvalue; - gint i; - - if (tuple == NULL) - return; - - if(!updating_enabled) { - current_ip = NULL; - G_FREE_CLEAR(current_file); - } - - something_changed = FALSE; - - if (fileinfo_win == NULL) - create_fileinfo_window(); - - if (!GTK_WIDGET_REALIZED(fileinfo_win)) - gtk_widget_realize(fileinfo_win); - - set_entry_str_from_field(entry_title, tuple, FIELD_TITLE, updating_enabled); - set_entry_str_from_field(entry_artist, tuple, FIELD_ARTIST, updating_enabled); - set_entry_str_from_field(entry_album, tuple, FIELD_ALBUM, updating_enabled); - set_entry_str_from_field(entry_comment, tuple, FIELD_COMMENT, updating_enabled); - set_entry_str_from_field(gtk_bin_get_child(GTK_BIN(entry_genre)), tuple, FIELD_GENRE, updating_enabled); - - tmp = g_strdup_printf ("%s%s", - tuple_get_string(tuple, FIELD_FILE_PATH, NULL), - tuple_get_string(tuple, FIELD_FILE_NAME, NULL)); - - if (tmp) { - fileinfo_entry_set_text(entry_location, tmp); - g_free(tmp); - } - - /* set empty string if field not availaible. --eugene */ - set_entry_int_from_field(entry_year, tuple, FIELD_YEAR, updating_enabled); - set_entry_int_from_field(entry_track, tuple, FIELD_TRACK_NUMBER, updating_enabled); - - fileinfo_label_set_text(label_format_name, tuple_get_string(tuple, FIELD_CODEC, NULL)); - fileinfo_label_set_text(label_quality, tuple_get_string(tuple, FIELD_QUALITY, NULL)); - - if (tuple_get_value_type(tuple, FIELD_BITRATE, NULL) == TUPLE_INT) { - tmp = g_strdup_printf(_("%d kb/s"), tuple_get_int(tuple, FIELD_BITRATE, NULL)); - fileinfo_label_set_text(label_bitrate, tmp); - g_free(tmp); - } else - fileinfo_label_set_text(label_bitrate, NULL); - - tmp = (gchar *)tuple_get_string(tuple, FIELD_MIMETYPE, NULL); - icon = mime_icon_lookup(48, tmp ? tmp : "audio/x-generic"); - if (icon) { - if (image_fileicon) gtk_image_set_from_pixbuf (GTK_IMAGE(image_fileicon), icon); - g_object_unref(icon); - } - - tmp = fileinfo_recursive_get_image( - tuple_get_string(tuple, FIELD_FILE_PATH, NULL), - tuple_get_string(tuple, FIELD_FILE_NAME, NULL), 0); - - if (tmp) { - fileinfo_entry_set_image(image_artwork, tmp); - g_free(tmp); - } - - gtk_widget_set_sensitive(btn_apply, FALSE); - - if (label_mini_status != NULL) { - gtk_label_set_text(GTK_LABEL(label_mini_status), "<span size=\"small\"></span>"); - gtk_label_set_use_markup(GTK_LABEL(label_mini_status), TRUE); - } - - store = gtk_list_store_new(RAWDATA_N_COLS, G_TYPE_STRING, G_TYPE_STRING); - - for (i = 0; i < FIELD_LAST; i++) { - gchar *key, *value; - - if (!tuple->values[i]) - continue; - - if (tuple->values[i]->type != TUPLE_INT && tuple->values[i]->value.string) - value = g_strdup(tuple->values[i]->value.string); - else if (tuple->values[i]->type == TUPLE_INT) - value = g_strdup_printf("%d", tuple->values[i]->value.integer); - else - continue; - - key = g_strdup(tuple_fields[i].name); - - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, - RAWDATA_KEY, key, - RAWDATA_VALUE, value, -1); - - g_free(key); - g_free(value); - } - - /* non-standard values are stored in a dictionary. */ - MOWGLI_DICTIONARY_FOREACH(tvalue, &state, tuple->dict) { - gchar *key, *value; - - if (tvalue->type != TUPLE_INT && tvalue->value.string) - value = g_strdup(tvalue->value.string); - else if (tvalue->type == TUPLE_INT) - value = g_strdup_printf("%d", tvalue->value.integer); - else - continue; - - key = g_strdup(state.cur->key); - - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, - RAWDATA_KEY, key, - RAWDATA_VALUE, value, -1); - - g_free(key); - g_free(value); - } - - gtk_tree_view_set_model(GTK_TREE_VIEW(treeview_rawdata), GTK_TREE_MODEL(store)); - g_object_unref(store); - - if (!GTK_WIDGET_VISIBLE(fileinfo_win)) - gtk_widget_show(fileinfo_win); -} - -static void fileinfo_show_editor_for_path (const gchar * path, InputPlugin * ip) -{ - G_FREE_CLEAR(current_file); - current_file = g_strdup(path); - current_ip = ip; - - Tuple *tuple = input_get_song_tuple(path); - - if (tuple == NULL) { - input_file_info_box(path); - return; - } - - fileinfo_show_for_tuple(tuple, TRUE); - - mowgli_object_unref(tuple); -} - -void ui_fileinfo_show (gint playlist, gint entry) -{ - const gchar * filename = playlist_entry_get_filename (playlist, entry); - InputPlugin * decoder = playlist_entry_get_decoder (playlist, entry); - Tuple * tuple; - - g_return_if_fail (filename != NULL); - - if (decoder == NULL) - decoder = file_probe (filename, FALSE); - - if (decoder == NULL) - { - gchar * message = g_strdup_printf ("No decoder found for %s.\n", - filename); - - hook_call ("interface show error", message); - g_free (message); - return; - } - - if (decoder->file_info_box != NULL) - decoder->file_info_box (filename); - else if (decoder->update_song_tuple != NULL && ! vfs_is_remote (filename)) - fileinfo_show_editor_for_path (filename, decoder); - else if ((tuple = (Tuple *) playlist_entry_get_tuple (playlist, entry)) != - NULL) - fileinfo_show_for_tuple (tuple, FALSE); - else if (decoder->get_song_tuple != NULL && (tuple = decoder->get_song_tuple - (filename)) != NULL) - { - fileinfo_show_for_tuple (tuple, FALSE); - playlist_entry_set_tuple (playlist, entry, tuple); - } - else - { - gchar * message = g_strdup_printf ("No info available for " - "%s.\n", filename); - - hook_call ("interface show error", message); - g_free (message); - } -} - -void ui_fileinfo_show_current (void) -{ - gint playlist = playlist_get_playing (); - - if (playlist == -1) - playlist = playlist_get_active (); - - ui_fileinfo_show (playlist, playlist_get_position (playlist)); -} diff --git a/src/audacious/ui_fileinfo.h b/src/audacious/ui_fileinfo.h deleted file mode 100644 index 0fc76b1..0000000 --- a/src/audacious/ui_fileinfo.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Audacious: A cross-platform multimedia player - * Copyright (c) 2006 William Pitcock, Tony Vroon, George Averill, - * Giacomo Lozito, Derek Pomery and Yoshiki Yazawa. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see <http://www.gnu.org/licenses>. - */ - -#ifndef AUDACIOUS_UI_FILEINFO_H -#define AUDACIOUS_UI_FILEINFO_H - -#include "tuple.h" -#include "plugin.h" -#include <glib.h> - -void create_fileinfo_window(void); -gchar* fileinfo_recursive_get_image(const gchar* path, const gchar* file_name, gint depth); - -void ui_fileinfo_show (gint playlist, gint entry); -void ui_fileinfo_show_current (void); - -#endif /* AUDACIOUS_UI_FILEINFO_H */ diff --git a/src/audacious/ui_fileinfopopup.c b/src/audacious/ui_fileinfopopup.c deleted file mode 100644 index e357576..0000000 --- a/src/audacious/ui_fileinfopopup.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Audacious: A cross-platform multimedia player - * Copyright (c) 2006 William Pitcock, Tony Vroon, George Averill, - * Giacomo Lozito, Derek Pomery and Yoshiki Yazawa. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses>. - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <glib.h> -#include <glib/gi18n.h> -#include <gtk/gtk.h> -#include <string.h> - -#include "compatibility.h" - -#include "main.h" -#include "playback.h" -#include "playlist-new.h" -#include "audstrings.h" -#include "ui_fileinfopopup.h" -#include "ui_fileinfo.h" - -static void -filepopup_entry_set_text(GtkWidget *filepopup_win, const gchar *entry_name, - const gchar *text) -{ - GtkWidget *widget = g_object_get_data(G_OBJECT(filepopup_win), entry_name); - g_return_if_fail(widget != NULL); - - gtk_label_set_text(GTK_LABEL(widget), text); -} - -static void -filepopup_entry_set_image(GtkWidget *filepopup_win, const gchar *entry_name, - const gchar *text) -{ - GtkWidget *widget = g_object_get_data(G_OBJECT(filepopup_win), entry_name); - GdkPixbuf *pixbuf, *pixbuf2; - int width, height; - double aspect; - - g_return_if_fail(widget != NULL); - - pixbuf = gdk_pixbuf_new_from_file(text, NULL); - g_return_if_fail(pixbuf != NULL); - - width = gdk_pixbuf_get_width(GDK_PIXBUF(pixbuf)); - height = gdk_pixbuf_get_height(GDK_PIXBUF(pixbuf)); - - if (strcmp(DATA_DIR "/images/audio.png", text)) - { - if (width == 0) - width = 1; - - aspect = (double)height / (double)width; - if (aspect > 1.0) { - height = (int)(cfg.filepopup_pixelsize * aspect); - width = cfg.filepopup_pixelsize; - } else { - height = cfg.filepopup_pixelsize; - width = (int)(cfg.filepopup_pixelsize / aspect); - } - - pixbuf2 = gdk_pixbuf_scale_simple(GDK_PIXBUF(pixbuf), width, height, - GDK_INTERP_BILINEAR); - g_object_unref(G_OBJECT(pixbuf)); - pixbuf = pixbuf2; - } - - gtk_image_set_from_pixbuf(GTK_IMAGE(widget), GDK_PIXBUF(pixbuf)); - g_object_unref(G_OBJECT(pixbuf)); -} - -static gboolean -fileinfopopup_progress_cb(gpointer filepopup_win) -{ - GtkWidget *progressbar = - g_object_get_data(G_OBJECT(filepopup_win), "progressbar"); - gchar *tooltip_file = g_object_get_data(G_OBJECT(filepopup_win), "file"); - gchar * current_file; - gint length = - GPOINTER_TO_INT(g_object_get_data(G_OBJECT(filepopup_win), "length")); - gint playlist, entry, time; - const gchar * filename; - - g_return_val_if_fail(progressbar != NULL, FALSE); - - playlist = playlist_get_active (); - entry = playlist_get_position (playlist); - filename = playlist_entry_get_filename (playlist, entry); - - if (filename == NULL) - return FALSE; - - current_file = g_filename_from_uri (filename, NULL, NULL); - - if (playback_get_playing() && length != -1 && - current_file != NULL && tooltip_file != NULL && - !strcmp(tooltip_file, current_file) && cfg.filepopup_showprogressbar) - { - time = playback_get_time(); - gchar *progress_time = - g_strdup_printf("%d:%02d", time / 60000, (time / 1000) % 60); - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressbar), - (gdouble)time / (gdouble)length); - gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progressbar), progress_time); - - if (!GTK_WIDGET_VISIBLE(progressbar)) - gtk_widget_show(progressbar); - - g_free(progress_time); - } - else - { - /* tooltip opened, but song is not the same, - * or playback is stopped, or length is not applicabile */ - if (GTK_WIDGET_VISIBLE(progressbar)) - gtk_widget_hide(progressbar); - } - - g_free( current_file ); - return TRUE; -} - -static gboolean -fileinfopopup_progress_check_active(GtkWidget *filepopup_win) -{ - if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(filepopup_win),"progress_sid")) == 0) - return FALSE; - return TRUE; -} - -static void -fileinfopopup_progress_init(GtkWidget *filepopup_win) -{ - g_object_set_data( G_OBJECT(filepopup_win) , "progress_sid" , GINT_TO_POINTER(0) ); -} - -static void -fileinfopopup_progress_start(GtkWidget *filepopup_win) -{ - gint sid = - g_timeout_add(500, (GSourceFunc)fileinfopopup_progress_cb, - filepopup_win); - g_object_set_data(G_OBJECT(filepopup_win), "progress_sid", - GINT_TO_POINTER(sid)); -} - -static void -fileinfopopup_progress_stop(GtkWidget *filepopup_win) -{ - gint sid = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(filepopup_win), - "progress_sid")); - if (sid != 0) - { - g_source_remove(sid); - g_object_set_data(G_OBJECT(filepopup_win),"progress_sid",GINT_TO_POINTER(0)); - } -} - -static void -fileinfopopup_add_category(GtkWidget *filepopup_win, - GtkWidget *filepopup_data_table, - const gchar *category, - const gchar *header_data, - const gchar *label_data, - const gint position) -{ - gchar *markup; - - GtkWidget *filepopup_data_info_header = gtk_label_new(""); - GtkWidget *filepopup_data_info_label = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(filepopup_data_info_header), 0, 0.5); - gtk_misc_set_alignment(GTK_MISC(filepopup_data_info_label), 0, 0.5); - gtk_misc_set_padding(GTK_MISC(filepopup_data_info_header), 0, 3); - gtk_misc_set_padding(GTK_MISC(filepopup_data_info_label), 0, 3); - - markup = - g_markup_printf_escaped("<span style=\"italic\">%s</span>", category); - - gtk_label_set_markup(GTK_LABEL(filepopup_data_info_header), markup); - g_free(markup); - - g_object_set_data(G_OBJECT(filepopup_win), header_data, - filepopup_data_info_header); - g_object_set_data(G_OBJECT(filepopup_win), label_data, - filepopup_data_info_label); - gtk_table_attach(GTK_TABLE(filepopup_data_table), - filepopup_data_info_header, - 0, 1, position, position + 1, GTK_FILL, 0, 0, 0); - gtk_table_attach(GTK_TABLE(filepopup_data_table), - filepopup_data_info_label, - 1, 2, position, position + 1, GTK_FILL, 0, 0, 0); -} - - - -GtkWidget * -fileinfopopup_create(void) -{ - GtkWidget *filepopup_win; - GtkWidget *filepopup_hbox; - GtkWidget *filepopup_data_image; - GtkWidget *filepopup_data_table; - GtkWidget *filepopup_progress; - - filepopup_win = gtk_window_new(GTK_WINDOW_POPUP); - gtk_window_set_type_hint(GTK_WINDOW(filepopup_win), - GDK_WINDOW_TYPE_HINT_TOOLTIP); - gtk_window_set_decorated(GTK_WINDOW(filepopup_win), FALSE); - gtk_container_set_border_width(GTK_CONTAINER(filepopup_win), 6); - - filepopup_hbox = gtk_hbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(filepopup_win), filepopup_hbox); - - filepopup_data_image = gtk_image_new(); - gtk_misc_set_alignment(GTK_MISC(filepopup_data_image), 0.5, 0); - gtk_image_set_from_file(GTK_IMAGE(filepopup_data_image), - DATA_DIR "/images/audio.png"); - - g_object_set_data(G_OBJECT(filepopup_win), "image_artwork", - filepopup_data_image); - g_object_set_data(G_OBJECT(filepopup_win), "last_artwork", NULL); - gtk_box_pack_start(GTK_BOX(filepopup_hbox), filepopup_data_image, - FALSE, FALSE, 0); - - gtk_box_pack_start(GTK_BOX(filepopup_hbox), gtk_vseparator_new(), - FALSE, FALSE, 6); - - filepopup_data_table = gtk_table_new(8, 2, FALSE); - gtk_table_set_row_spacings(GTK_TABLE(filepopup_data_table), 0); - gtk_table_set_col_spacings(GTK_TABLE(filepopup_data_table), 6); - gtk_box_pack_start(GTK_BOX(filepopup_hbox), filepopup_data_table, - TRUE, TRUE, 0); - - fileinfopopup_add_category(filepopup_win, filepopup_data_table, - _("Title"), - "header_title", "label_title", 0); - fileinfopopup_add_category(filepopup_win, filepopup_data_table, - _("Artist"), - "header_artist", "label_artist", 1); - fileinfopopup_add_category(filepopup_win, filepopup_data_table, - _("Album"), - "header_album", "label_album", 2); - fileinfopopup_add_category(filepopup_win, filepopup_data_table, - _("Genre"), - "header_genre", "label_genre", 3); - fileinfopopup_add_category(filepopup_win, filepopup_data_table, - _("Year"), - "header_year", "label_year", 4); - fileinfopopup_add_category(filepopup_win, filepopup_data_table, - _("Track Number"), - "header_tracknum", "label_tracknum", - 5); - fileinfopopup_add_category(filepopup_win, filepopup_data_table, - _("Track Length"), - "header_tracklen", "label_tracklen", - 6); - - gtk_table_set_row_spacing(GTK_TABLE(filepopup_data_table), 6, 6); - - /* track progress */ - filepopup_progress = gtk_progress_bar_new(); - gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(filepopup_progress), - GTK_PROGRESS_LEFT_TO_RIGHT); - gtk_progress_bar_set_text(GTK_PROGRESS_BAR(filepopup_progress), ""); - gtk_table_attach(GTK_TABLE(filepopup_data_table), filepopup_progress, - 0, 2, 7, 8, GTK_FILL, 0, 0, 0); - g_object_set_data(G_OBJECT(filepopup_win), "file", NULL); - g_object_set_data(G_OBJECT(filepopup_win), "progressbar", - filepopup_progress); - fileinfopopup_progress_init(filepopup_win); - - /* this will realize all widgets contained in filepopup_hbox */ - gtk_widget_show_all(filepopup_hbox); - - /* do not show the track progress */ - gtk_widget_hide(filepopup_progress); - - return filepopup_win; -} - -void -fileinfopopup_destroy(GtkWidget *filepopup_win) -{ - gchar *last_artwork; - fileinfopopup_progress_stop(filepopup_win); - - last_artwork = - g_object_get_data(G_OBJECT(filepopup_win), "last_artwork"); - if (last_artwork != NULL) - g_free(last_artwork); - - gtk_widget_destroy(filepopup_win); -} - -static void -fileinfopupup_update_data(GtkWidget *filepopup_win, - const gchar *text, - const gchar *label_data, - const gchar *header_data) -{ - if (text != NULL) - { - filepopup_entry_set_text(filepopup_win, label_data, text); - gtk_widget_show(GTK_WIDGET(g_object_get_data(G_OBJECT(filepopup_win), header_data))); - gtk_widget_show(GTK_WIDGET(g_object_get_data(G_OBJECT(filepopup_win), label_data))); - } - else - { - gtk_widget_hide(GTK_WIDGET(g_object_get_data(G_OBJECT(filepopup_win), header_data))); - gtk_widget_hide(GTK_WIDGET(g_object_get_data(G_OBJECT(filepopup_win), label_data))); - } -} - -void -fileinfopopup_show_from_tuple(GtkWidget *filepopup_win, - Tuple *tuple) -{ - gchar *tmp = NULL; - gint x, y, x_off = 3, y_off = 3, h, w; - gchar *length_string, *year_string, *track_string; - gchar *last_artwork; - const static gchar default_artwork[] = DATA_DIR "/images/audio.png"; - gint length; - const gchar * path, * name; - - last_artwork = - g_object_get_data(G_OBJECT(filepopup_win), "last_artwork"); - - g_return_if_fail(tuple != NULL); - - tmp = g_object_get_data(G_OBJECT(filepopup_win), "file"); - if (tmp != NULL) { - g_free(tmp); - tmp = NULL; - g_object_set_data(G_OBJECT(filepopup_win), "file", NULL); - } - - path = tuple_get_string (tuple, FIELD_FILE_PATH, NULL); - - if (!path || strncmp (path, "file://", 7)) /* remote files not handled */ - return; - - path += 7; - name = tuple_get_string (tuple, FIELD_FILE_NAME, NULL); - - g_object_set_data ((GObject *) filepopup_win, "file", g_build_filename - (path, name, NULL)); - - gtk_widget_realize(filepopup_win); - - if (tuple_get_string(tuple, FIELD_TITLE, NULL)) - { - gchar *markup = - g_markup_printf_escaped("<span style=\"italic\">%s</span>", _("Title")); - gtk_label_set_markup(GTK_LABEL(g_object_get_data(G_OBJECT(filepopup_win), "header_title")), markup); - g_free(markup); - filepopup_entry_set_text(filepopup_win, "label_title", tuple_get_string(tuple, FIELD_TITLE, NULL)); - } - else - { - /* display filename if track_name is not available */ - gchar *markup = - g_markup_printf_escaped("<span style=\"italic\">%s</span>", _("Filename")); - gtk_label_set_markup(GTK_LABEL(g_object_get_data(G_OBJECT(filepopup_win), "header_title")), markup); - g_free(markup); - filepopup_entry_set_text (filepopup_win, "label_title", name); - } - - fileinfopupup_update_data(filepopup_win, tuple_get_string(tuple, FIELD_ARTIST, NULL), - "label_artist", "header_artist"); - fileinfopupup_update_data(filepopup_win, tuple_get_string(tuple, FIELD_ALBUM, NULL), - "label_album", "header_album"); - fileinfopupup_update_data(filepopup_win, tuple_get_string(tuple, FIELD_GENRE, NULL), - "label_genre", "header_genre"); - - length = tuple_get_int(tuple, FIELD_LENGTH, NULL); - length_string = (length > 0) ? - g_strdup_printf("%d:%02d", length / 60000, (length / 1000) % 60) : NULL; - fileinfopupup_update_data(filepopup_win, length_string, - "label_tracklen", "header_tracklen"); - g_free(length_string); - - if ( length > 0 ) - g_object_set_data( G_OBJECT(filepopup_win), "length" , GINT_TO_POINTER(length) ); - else - g_object_set_data( G_OBJECT(filepopup_win), "length" , GINT_TO_POINTER(-1) ); - - year_string = (tuple_get_int(tuple, FIELD_YEAR, NULL) == 0) ? NULL : g_strdup_printf("%d", tuple_get_int(tuple, FIELD_YEAR, NULL)); - fileinfopupup_update_data(filepopup_win, year_string, - "label_year", "header_year"); - g_free(year_string); - - track_string = (tuple_get_int(tuple, FIELD_TRACK_NUMBER, NULL) == 0) ? NULL : g_strdup_printf("%d", tuple_get_int(tuple, FIELD_TRACK_NUMBER, NULL)); - fileinfopupup_update_data(filepopup_win, track_string, - "label_tracknum", "header_tracknum"); - g_free(track_string); - - tmp = fileinfo_recursive_get_image (path, name, 0); - - /* { */ - if (tmp) { // picture found - if (!last_artwork || strcmp(last_artwork, tmp)) { // new picture - filepopup_entry_set_image(filepopup_win, "image_artwork", tmp); - if (last_artwork) g_free(last_artwork); - last_artwork = tmp; - g_object_set_data(G_OBJECT(filepopup_win), "last_artwork", last_artwork); - } - else { // same picture - } - } - else { // no picture found - if (!last_artwork || strcmp(last_artwork, default_artwork)) { - filepopup_entry_set_image(filepopup_win, "image_artwork", default_artwork); - if (last_artwork) g_free(last_artwork); - last_artwork = g_strdup(default_artwork); - g_object_set_data(G_OBJECT(filepopup_win), "last_artwork", last_artwork); - } - else { - } - } - /* } */ - - /* start a timer that updates a progress bar if the tooltip - is shown for the song that is being currently played */ - if (fileinfopopup_progress_check_active(filepopup_win) == FALSE) - { - fileinfopopup_progress_start(filepopup_win); - /* immediately run the callback once to update progressbar status */ - fileinfopopup_progress_cb(filepopup_win); - } - - gdk_window_get_pointer(gdk_get_default_root_window(), &x, &y, NULL); - gtk_window_get_size(GTK_WINDOW(filepopup_win), &w, &h); - if (gdk_screen_width()-(w+3) < x) x_off = (w*-1)-3; - if (gdk_screen_height()-(h+3) < y) y_off = (h*-1)-3; - gtk_window_move(GTK_WINDOW(filepopup_win), x + x_off, y + y_off); - - gtk_widget_show(filepopup_win); -} - -void -fileinfopopup_show_from_title(GtkWidget *filepopup_win, gchar *title) -{ - Tuple * tuple = tuple_new(); - tuple_associate_string(tuple, FIELD_TITLE, NULL, title); - fileinfopopup_show_from_tuple(filepopup_win, tuple); - mowgli_object_unref(tuple); - return; -} - -void -fileinfopopup_hide(GtkWidget *filepopup_win, gpointer unused) -{ - if (GTK_WIDGET_VISIBLE(filepopup_win)) - { - fileinfopopup_progress_stop(filepopup_win); - - gtk_widget_hide(filepopup_win); - - filepopup_entry_set_text(GTK_WIDGET(filepopup_win), "label_title", ""); - filepopup_entry_set_text(GTK_WIDGET(filepopup_win), "label_artist", ""); - filepopup_entry_set_text(GTK_WIDGET(filepopup_win), "label_album", ""); - filepopup_entry_set_text(GTK_WIDGET(filepopup_win), "label_genre", ""); - filepopup_entry_set_text(GTK_WIDGET(filepopup_win), "label_tracknum", ""); - filepopup_entry_set_text(GTK_WIDGET(filepopup_win), "label_year", ""); - filepopup_entry_set_text(GTK_WIDGET(filepopup_win), "label_tracklen", ""); - - gtk_window_resize(GTK_WINDOW(filepopup_win), 1, 1); - } -} diff --git a/src/audacious/ui_fileinfopopup.h b/src/audacious/ui_fileinfopopup.h deleted file mode 100644 index 0b19634..0000000 --- a/src/audacious/ui_fileinfopopup.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Audacious: A cross-platform multimedia player - * Copyright (c) 2006 William Pitcock, Tony Vroon, George Averill, - * Giacomo Lozito, Derek Pomery and Yoshiki Yazawa. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef AUDACIOUS_UI_FILEINFOPOPUP_H -#define AUDACIOUS_UI_FILEINFOPOPUP_H - -#include "libaudcore/tuple.h" -#include <gtk/gtk.h> - -/* create/destroy */ -GtkWidget* fileinfopopup_create(void); -void fileinfopopup_destroy(GtkWidget* fileinfopopup_win); - -/* show/hide */ -void fileinfopopup_show_from_tuple(GtkWidget *fileinfopopup_win, Tuple *tuple); -void fileinfopopup_show_from_title(GtkWidget *fileinfopopup_win, gchar *title); -void fileinfopopup_hide(GtkWidget *filepopup_win, gpointer unused); - -#endif /* AUDACIOUS_UI_FILEINFOPOPUP_H */ diff --git a/src/audacious/ui_misc.h b/src/audacious/ui_misc.h index 9f010ae..abf5220 100644 --- a/src/audacious/ui_misc.h +++ b/src/audacious/ui_misc.h @@ -18,7 +18,6 @@ */ #include <glib/gi18n.h> -#include <gtk/gtk.h> #ifndef _AUDACIOUS_UI_MISC_H diff --git a/src/audacious/ui_plugin_menu.c b/src/audacious/ui_plugin_menu.c index 49f7e0b..5f2846a 100644 --- a/src/audacious/ui_plugin_menu.c +++ b/src/audacious/ui_plugin_menu.c @@ -57,7 +57,8 @@ static void static_menu_init (StaticMenu * menu) g_object_ref (menu); } -GtkWidget * get_plugin_menu (gint id) +/* GtkWidget * get_plugin_menu (gint id) */ +void * get_plugin_menu (gint id) { static gboolean initted = FALSE; static GtkWidget * menus[TOTAL_PLUGIN_MENUS]; @@ -81,13 +82,15 @@ GtkWidget * get_plugin_menu (gint id) return menus[id]; } -gint menu_plugin_item_add (gint id, GtkWidget * item) +/* gint menu_plugin_item_add (gint id, GtkWidget * item) */ +gint menu_plugin_item_add (gint id, void * item) { gtk_menu_shell_append ((GtkMenuShell *) get_plugin_menu (id), item); return 0; } -gint menu_plugin_item_remove (gint id, GtkWidget * item) +/* gint menu_plugin_item_remove (gint id, GtkWidget * item) */ +gint menu_plugin_item_remove (gint id, void * item) { gtk_container_remove ((GtkContainer *) get_plugin_menu (id), item); return 0; diff --git a/src/audacious/ui_plugin_menu.h b/src/audacious/ui_plugin_menu.h index 9cdb267..c7377e7 100644 --- a/src/audacious/ui_plugin_menu.h +++ b/src/audacious/ui_plugin_menu.h @@ -1,5 +1,5 @@ /* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2009 Audacious development team. + * Copyright (C) 2005-2010 Audacious development team. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,9 +21,6 @@ #define AUDACIOUS_UI_PLUGIN_MENU_H #include <glib.h> -#include <gtk/gtk.h> - -G_BEGIN_DECLS #define AUDACIOUS_MENU_MAIN 0 #define AUDACIOUS_MENU_PLAYLIST 1 @@ -34,10 +31,11 @@ G_BEGIN_DECLS #define AUDACIOUS_MENU_PLAYLIST_MISC 6 #define TOTAL_PLUGIN_MENUS 7 -GtkWidget * get_plugin_menu (gint id); -gint menu_plugin_item_add (gint id, GtkWidget * item); -gint menu_plugin_item_remove (gint id, GtkWidget * item); - -G_END_DECLS +/* GtkWidget * get_plugin_menu (gint id); */ +void * get_plugin_menu (gint id); +/* gint menu_plugin_item_add (gint id, GtkWidget * item); */ +gint menu_plugin_item_add (gint id, void * item); +/* gint menu_plugin_item_remove (gint id, GtkWidget * item); */ +gint menu_plugin_item_remove (gint id, void * item); #endif /* AUDACIOUS_UI_PLUGIN_MENU_H */ diff --git a/src/audacious/ui_preferences.c b/src/audacious/ui_preferences.c index 45ce152..4745a3f 100644 --- a/src/audacious/ui_preferences.c +++ b/src/audacious/ui_preferences.c @@ -54,8 +54,6 @@ #include "ui_preferences.h" -#include "build_stamp.h" - #define TITLESTRING_UPDATE_TIMEOUT 3 static void sw_volume_toggled (void); @@ -157,6 +155,7 @@ static ComboBoxElements chardet_detector_presets[] = { { N_("Hebrew") , N_("Hebrew") }, { N_("Turkish") , N_("Turkish") }, { N_("Arabic") , N_("Arabic") }, + { N_("Polish") , N_("Polish") }, { N_("Universal"), N_("Universal") } }; @@ -170,8 +169,8 @@ static ComboBoxElements bitdepth_elements[] = { typedef struct { void *next; GtkWidget *container; - char *pg_name; - char *img_url; + const gchar * pg_name; + const gchar * img_url; } CategoryQueueEntry; CategoryQueueEntry *category_queue = NULL; @@ -1561,7 +1560,9 @@ static void fill_table (GtkWidget * table, PreferencesWidget * elements, gint } } -void create_widgets_with_domain (GtkBox * box, PreferencesWidget * widgets, gint +/* void create_widgets_with_domain (GtkBox * box, PreferencesWidget * widgets, + gint amt, const gchar * domain) */ +void create_widgets_with_domain (void * box, PreferencesWidget * widgets, gint amt, const gchar * domain) { gint x; @@ -2552,8 +2553,8 @@ create_plugin_pages(void) create_plugin_page(get_effect_enabled_list()); } -GtkWidget ** -create_prefs_window(void) +/* GtkWidget * * create_prefs_window (void) */ +void * * create_prefs_window (void) { gchar *aud_version_string; @@ -2655,16 +2656,15 @@ create_prefs_window(void) /* audacious version label */ - aud_version_string = g_strdup_printf("<span size='small'>%s (%s) (%s@%s)</span>", - "Audacious " PACKAGE_VERSION , - build_stamp , - g_get_user_name() , g_get_host_name() ); + aud_version_string = g_strdup_printf + ("<span size='small'>%s (%s)</span>", "Audacious " PACKAGE_VERSION, + BUILDSTAMP); gtk_label_set_markup( GTK_LABEL(audversionlabel) , aud_version_string ); g_free(aud_version_string); gtk_widget_show_all(vbox); - return &prefswin; + return (void * *) & prefswin; } void @@ -2722,8 +2722,8 @@ hide_prefs_window(void) gtk_widget_hide(GTK_WIDGET(prefswin)); } -static void -prefswin_page_queue_new(GtkWidget *container, gchar *name, gchar *imgurl) +static void prefswin_page_queue_new (GtkWidget * container, const gchar * name, + const gchar * imgurl) { CategoryQueueEntry *ent = g_new0(CategoryQueueEntry, 1); @@ -2755,8 +2755,10 @@ prefswin_page_queue_destroy(CategoryQueueEntry *ent) * * - nenolod */ -gint -prefswin_page_new(GtkWidget *container, gchar *name, gchar *imgurl) +/* gint prefswin_page_new (GtkWidget * container, const gchar * name, + const gchar * imgurl) */ +gint prefswin_page_new (void * container, const gchar * name, const gchar * + imgurl) { GtkTreeModel *model; GtkTreeIter iter; diff --git a/src/audacious/ui_preferences.h b/src/audacious/ui_preferences.h index 3ede72f..b709a81 100644 --- a/src/audacious/ui_preferences.h +++ b/src/audacious/ui_preferences.h @@ -20,12 +20,16 @@ #ifndef AUDACIOUS_UI_PREFERENCES_H #define AUDACIOUS_UI_PREFERENCES_H -GtkWidget** create_prefs_window(void); +/* GtkWidget * * create_prefs_window (void); */ +void * * create_prefs_window (void); void destroy_prefs_window(void); void show_prefs_window(void); void hide_prefs_window(void); -gint prefswin_page_new(GtkWidget *container, gchar *name, gchar *imgurl); +/* gint prefswin_page_new (GtkWidget * container, const gchar * name, + const gchar * imgurl); */ +gint prefswin_page_new (void * container, const gchar * name, const gchar * + imgurl); void prefswin_page_destroy(GtkWidget *container); #endif /* AUDACIOUS_UI_PREFERENCES_H */ diff --git a/src/audacious/util.c b/src/audacious/util.c index 9177668..17389f9 100644 --- a/src/audacious/util.c +++ b/src/audacious/util.c @@ -163,9 +163,9 @@ open_ini_file(const gchar *filename) GHashTable *section = NULL; GString *section_name, *key_name, *value; gpointer section_hash, key_hash; - gchar *buffer = NULL; + guchar * buffer = NULL; gsize off = 0; - gsize filesize = 0; + gint64 filesize = 0; unsigned char x[] = { 0xff, 0xfe, 0x00 }; @@ -181,7 +181,7 @@ open_ini_file(const gchar *filename) */ if (filesize > 2 && !memcmp(&buffer[0],&x,2)) { - gchar *outbuf = g_malloc (filesize); /* it's safe to waste memory. */ + guchar * outbuf = g_malloc (filesize); /* it's safe to waste memory. */ guint counter; for (counter = 2; counter < filesize; counter += 2) @@ -483,74 +483,6 @@ dir_foreach(const gchar * path, DirForeachFunc function, } /** - * util_info_dialog: - * @title: The title of the message to show. - * @text: The text of the message to show. - * @button_text: The text of the button which will close the messagebox. - * @modal: Whether or not the messagebox should be modal. - * @button_action: Code to execute on when the messagebox is closed, or %NULL. - * @action_data: Optional opaque data to pass to @button_action. - * - * Displays a message box. - * - * Return value: A GTK widget handle for the message box. - **/ -GtkWidget * -util_info_dialog(const gchar * title, const gchar * text, - const gchar * button_text, gboolean modal, - GCallback button_action, gpointer action_data) -{ - GtkWidget *dialog; - GtkWidget *dialog_vbox, *dialog_hbox, *dialog_bbox; - GtkWidget *dialog_bbox_b1; - GtkWidget *dialog_textlabel; - GtkWidget *dialog_icon; - - dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_type_hint( GTK_WINDOW(dialog) , GDK_WINDOW_TYPE_HINT_DIALOG ); - gtk_window_set_modal( GTK_WINDOW(dialog) , modal ); - gtk_window_set_title( GTK_WINDOW(dialog) , title ); - gtk_container_set_border_width( GTK_CONTAINER(dialog) , 10 ); - - dialog_vbox = gtk_vbox_new( FALSE , 0 ); - dialog_hbox = gtk_hbox_new( FALSE , 0 ); - - /* icon */ - dialog_icon = gtk_image_new_from_stock( GTK_STOCK_DIALOG_INFO , GTK_ICON_SIZE_DIALOG ); - gtk_box_pack_start( GTK_BOX(dialog_hbox) , dialog_icon , FALSE , FALSE , 2 ); - - /* label */ - dialog_textlabel = gtk_label_new( text ); - /* gtk_label_set_selectable( GTK_LABEL(dialog_textlabel) , TRUE ); */ - gtk_box_pack_start( GTK_BOX(dialog_hbox) , dialog_textlabel , TRUE , TRUE , 2 ); - - gtk_box_pack_start( GTK_BOX(dialog_vbox) , dialog_hbox , FALSE , FALSE , 2 ); - gtk_box_pack_start( GTK_BOX(dialog_vbox) , gtk_hseparator_new() , FALSE , FALSE , 4 ); - - dialog_bbox = gtk_hbutton_box_new(); - gtk_button_box_set_layout( GTK_BUTTON_BOX(dialog_bbox) , GTK_BUTTONBOX_END ); - dialog_bbox_b1 = gtk_button_new_with_label( button_text ); - g_signal_connect_swapped( G_OBJECT(dialog_bbox_b1) , "clicked" , - G_CALLBACK(gtk_widget_destroy) , dialog ); - if ( button_action ) - g_signal_connect( G_OBJECT(dialog_bbox_b1) , "clicked" , - button_action , action_data ); - - gtk_container_add( GTK_CONTAINER(dialog_bbox) , dialog_bbox_b1 ); - gtk_box_pack_start( GTK_BOX(dialog_vbox) , dialog_bbox , FALSE , FALSE , 0 ); - - gtk_container_add( GTK_CONTAINER(dialog) , dialog_vbox ); - - GTK_WIDGET_SET_FLAGS( dialog_bbox_b1 , GTK_CAN_DEFAULT); - gtk_widget_grab_default( dialog_bbox_b1 ); - - gtk_widget_show_all(dialog); - - return dialog; -} - - -/** * util_get_localdir: * * Returns a string with the full path of Audacious local datadir (where config files are placed). @@ -614,22 +546,6 @@ construct_uri(gchar *string, const gchar *playlist_name) // uri, path and anythi return uri; } -/* - * minimize number of realloc's: - * - set N to nearest power of 2 not less then N - * - double it - * - * -- asphyx - * - * XXX: what's so smart about this?? seems wasteful and silly. --nenolod - */ -gpointer -smart_realloc(gpointer ptr, gsize *size) -{ - *size = (gsize)pow(2, ceil(log(*size) / log(2)) + 1); - return g_realloc(ptr, *size); -} - /* local files -- not URI's */ gint file_get_mtime (const gchar * filename) { diff --git a/src/audacious/util.h b/src/audacious/util.h index e7df139..e02dc93 100644 --- a/src/audacious/util.h +++ b/src/audacious/util.h @@ -71,18 +71,10 @@ gboolean text_get_extents(const gchar * fontname, const gchar * text, guint gint_count_digits(gint n); - -GtkWidget *util_info_dialog(const gchar * title, const gchar * text, - const gchar * button_text, gboolean modal, GCallback button_action, - gpointer action_data); - gchar *util_get_localdir(void); gchar *construct_uri(gchar *string, const gchar *playlist_name); -/* minimizes number of realloc's */ -gpointer smart_realloc(gpointer ptr, gsize *size); - gint file_get_mtime (const gchar * filename); void make_directory(const gchar * path, mode_t mode); diff --git a/src/audacious/visualization.c b/src/audacious/visualization.c index 038d2eb..e55a95f 100644 --- a/src/audacious/visualization.c +++ b/src/audacious/visualization.c @@ -26,6 +26,7 @@ #include "visualization.h" #include <glib.h> +#include <gtk/gtk.h> #include <math.h> #include <string.h> diff --git a/src/audtool/Makefile b/src/audtool/Makefile index 9ba6290..df743a1 100644 --- a/src/audtool/Makefile +++ b/src/audtool/Makefile @@ -29,7 +29,7 @@ LIBS += ${DBUS_LIBS} \ install-extra: if test -h "${DESTDIR}${bindir}/audtool" ; then ${RM} "${DESTDIR}${bindir}/audtool" ; fi mkdir -p "${DESTDIR}${bindir}" - ${LN_S} "${DESTDIR}${bindir}/audtool2" "${DESTDIR}${bindir}/audtool" + ${LN_S} audtool2 "${DESTDIR}${bindir}/audtool" uninstall-extra: if test -h "${DESTDIR}${bindir}/audtool" ; then ${RM} "${DESTDIR}${bindir}/audtool" ; fi diff --git a/src/libaudacious++/Makefile b/src/libaudacious++/Makefile deleted file mode 100644 index e50f022..0000000 --- a/src/libaudacious++/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -PACKAGE = audacious++ -STATIC_LIB = libaudacious++.a -SRCS = plugin.cxx - -include ../../buildsys.mk -include ../../extra.mk diff --git a/src/libaudacious++/README b/src/libaudacious++/README deleted file mode 100644 index 6f34c43..0000000 --- a/src/libaudacious++/README +++ /dev/null @@ -1 +0,0 @@ -this is a work in progress. it's not GPL yet. don't use it. --nenolod diff --git a/src/libaudacious++/plugin.h b/src/libaudacious++/plugin.h deleted file mode 100644 index a915771..0000000 --- a/src/libaudacious++/plugin.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2008 William Pitcock <nenolod@sacredspiral.co.uk> - * - * [insert GPL license here later] - */ - -#ifndef __AUDACIOUSXX__PLUGIN_H_GUARD -#define __AUDACIOUSXX__PLUGIN_H_GUARD - -#include <string> - -namespace Audacious { - -class Plugin { -private: - std::string name; - std::string description; - -public: - Plugin(std::string name_, std::string description_); - ~Plugin(); -}; - -class VisPlugin : Plugin { -private: - int pcm_channels; - int freq_channels; - -public: - VisPlugin(std::string name_, std::string description, int pc, int fc); - ~VisPlugin(); -}; - -}; - -#endif diff --git a/src/libaudcore/audio.c b/src/libaudcore/audio.c index c4b8084..1975cfe 100644 --- a/src/libaudcore/audio.c +++ b/src/libaudcore/audio.c @@ -28,7 +28,7 @@ static void NAME (TYPE * in, gfloat * out, gint samples) \ { \ TYPE * end = in + samples; \ while (in < end) \ - * out ++ = (gfloat) (TYPE) (SWAP (* in ++) - OFFSET) / RANGE; \ + * out ++ = (TYPE) (SWAP (* in ++) - OFFSET) / (gdouble) RANGE; \ } #define TO_INT_LOOP(NAME, TYPE, SWAP, OFFSET, RANGE) \ @@ -38,7 +38,7 @@ static void NAME (gfloat * in, TYPE * out, gint samples) \ while (in < end) \ { \ float f = * in ++; \ - * out ++ = SWAP (OFFSET + (TYPE) (CLAMP (f, -1, 1) * RANGE)); \ + * out ++ = SWAP (OFFSET + (TYPE) (CLAMP (f, -1, 1) * (gdouble) RANGE)); \ } \ } diff --git a/src/libaudcore/audstrings.c b/src/libaudcore/audstrings.c index 04b8377..b7428fe 100644 --- a/src/libaudcore/audstrings.c +++ b/src/libaudcore/audstrings.c @@ -93,20 +93,6 @@ str_replace_drive_letter(gchar * str) return str; } -static gchar * -str_replace_char(gchar * str, gchar o, gchar n) -{ - gchar *match; - - g_return_val_if_fail(str != NULL, NULL); - - match = str; - while ((match = strchr(match, o)) != NULL) - *match = n; - - return str; -} - gchar * str_append(gchar * str, const gchar * add_str) { @@ -312,7 +298,7 @@ convert_dos_path(gchar * path) str_replace_drive_letter(path); /* replace '\' with '/' */ - str_replace_char(path, '\\', '/'); + string_replace_char (path, '\\', '/'); return path; } @@ -377,6 +363,12 @@ filename_split_subtune(const gchar * filename, gint * track) return result; } +void string_replace_char (gchar * string, gchar old_str, gchar new_str) +{ + while ((string = strchr (string, old_str)) != NULL) + * string = new_str; +} + static gchar get_hex_digit(gchar **get) { gchar c = **get; @@ -394,6 +386,7 @@ static gchar get_hex_digit(gchar **get) return c - '0'; } +/* modifies string in place */ void string_decode_percent(gchar *string) { gchar *get = string; @@ -411,6 +404,58 @@ void string_decode_percent(gchar *string) *set = 0; } +/* we encode any character except the "unreserved" characters of RFC 3986 and + * (optionally) the forward slash */ +static gboolean is_legal_char (gchar c, gboolean is_filename) +{ + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= + '9') || (strchr ("-_.~", c) != NULL) || (is_filename && c == '/'); +} + +static gchar make_hex_digit (gint i) +{ + if (i < 10) + return '0' + i; + else + return ('A' - 10) + i; +} + +/* is_filename specifies whether the forward slash should be left intact */ +/* returns string allocated with g_malloc */ +gchar * string_encode_percent (const gchar * string, gboolean is_filename) +{ + gint length = 0; + const gchar * get; + gchar c; + gchar * new, * set; + + for (get = string; (c = * get); get ++) + { + if (is_legal_char (c, is_filename)) + length ++; + else + length += 3; + } + + new = g_malloc (length + 1); + set = new; + + for (get = string; (c = * get); get ++) + { + if (is_legal_char (c, is_filename)) + * set ++ = c; + else + { + * set ++ = '%'; + * set ++ = make_hex_digit (((guchar) c) >> 4); + * set ++ = make_hex_digit (c & 0xF); + } + } + + * set = 0; + return new; +} + void string_cut_extension(gchar *string) { gchar *period = strrchr(string, '.'); @@ -464,3 +509,28 @@ gint string_compare (const gchar * a, const gchar * b) return 0; } + +const void * memfind (const void * mem, gint size, const void * token, gint + length) +{ + if (! length) + return mem; + + size -= length - 1; + + while (size > 0) + { + const void * maybe = memchr (mem, * (guchar *) token, size); + + if (maybe == NULL) + return NULL; + + if (! memcmp (maybe, token, length)) + return maybe; + + size -= (guchar *) maybe + 1 - (guchar *) mem; + mem = (guchar *) maybe + 1; + } + + return NULL; +} diff --git a/src/libaudcore/audstrings.h b/src/libaudcore/audstrings.h index e96d52f..5baf067 100644 --- a/src/libaudcore/audstrings.h +++ b/src/libaudcore/audstrings.h @@ -60,10 +60,15 @@ extern gchar *(*chardet_to_utf8)(const gchar *str, gssize len, gchar *filename_get_subtune(const gchar * filename, gint * track); gchar *filename_split_subtune(const gchar * filename, gint * track); -void string_decode_percent(gchar *string); +void string_replace_char (gchar * string, gchar old_str, gchar new_str); +void string_decode_percent (gchar * string); +gchar * string_encode_percent (const gchar * string, gboolean is_filename); void string_cut_extension(gchar *string); gint string_compare (const gchar * a, const gchar * b); +const void * memfind (const void * mem, gint size, const void * token, gint + length); + G_END_DECLS #endif /* AUDACIOUS_STRINGS_H */ diff --git a/src/libaudcore/index.c b/src/libaudcore/index.c index db1cea8..9344e7b 100644 --- a/src/libaudcore/index.c +++ b/src/libaudcore/index.c @@ -1,12 +1,12 @@ /* * index.c - * Copyright 2009 John Lindgren + * Copyright 2009-2010 John Lindgren * * This file is part of Audacious. * * Audacious is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software - * Foundation, version 3 of the License. + * Foundation, version 2 or version 3 of the License. * * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR @@ -29,7 +29,9 @@ struct index { void * * data; - gint length, size; + gint count, size; + gint (* compare) (const void * a, const void * b, void * data); + void * compare_data; }; struct index * index_new (void) @@ -37,8 +39,10 @@ struct index * index_new (void) struct index * index = g_malloc (sizeof (struct index)); index->data = NULL; - index->length = 0; + index->count = 0; index->size = 0; + index->compare = NULL; + index->compare_data = NULL; return index; } @@ -51,7 +55,7 @@ void index_free (struct index * index) gint index_count (struct index * index) { - return index->length; + return index->count; } void index_set (struct index * index, gint at, void * value) @@ -80,12 +84,12 @@ static void resize_to (struct index * index, gint size) } } -static void make_room (struct index * index, gint at, gint length) +static void make_room (struct index * index, gint at, gint count) { - resize_to (index, index->length + length); - memmove (index->data + at + length, index->data + at, sizeof (void *) * - (index->length - at)); - index->length += length; + resize_to (index, index->count + count); + memmove (index->data + at + count, index->data + at, sizeof (void *) * + (index->count - at)); + index->count += count; } void index_insert (struct index * index, gint at, void * value) @@ -96,35 +100,80 @@ void index_insert (struct index * index, gint at, void * value) void index_append (struct index * index, void * value) { - resize_to (index, index->length + 1); - index->data[index->length] = value; - index->length ++; + index_insert (index, index->count, value); +} + +void index_copy_set (struct index * source, gint from, struct index * target, + gint to, gint count) +{ + memcpy (target->data + to, source->data + from, sizeof (void *) * count); +} + +void index_copy_insert (struct index * source, gint from, struct index * target, + gint to, gint count) +{ + make_room (target, to, count); + memcpy (target->data + to, source->data + from, sizeof (void *) * count); +} + +void index_copy_append (struct index * source, gint from, struct index * target, + gint count) +{ + index_copy_insert (source, from, target, target->count, count); } void index_merge_insert (struct index * first, gint at, struct index * second) { - make_room (first, at, second->length); - memcpy (first->data + at, second->data, sizeof (void *) * second->length); + index_copy_insert (second, 0, first, at, second->count); } void index_merge_append (struct index * first, struct index * second) { - resize_to (first, first->length + second->length); - memcpy (first->data + first->length, second->data, sizeof (void *) * - second->length); - first->length += second->length; + index_copy_insert (second, 0, first, first->count, second->count); +} + +void index_move (struct index * index, gint from, gint to, gint count) +{ + memmove (index->data + to, index->data + from, sizeof (void *) * count); } -void index_delete (struct index * index, gint at, gint length) +void index_delete (struct index * index, gint at, gint count) { - index->length -= length; - memmove (index->data + at, index->data + at + length, sizeof (void *) * - (index->length - at)); + index->count -= count; + memmove (index->data + at, index->data + at + count, sizeof (void *) * + (index->count - at)); +} + +static gint index_compare (const void * a, const void * b, void * _compare) +{ + gint (* compare) (const void *, const void *) = _compare; + + return compare (* (const void * *) a, * (const void * *) b); +} + +void index_sort (struct index * index, gint (* compare) (const void *, const + void *)) +{ + g_qsort_with_data (index->data, index->count, sizeof (void *), + index_compare, compare); +} + +static gint index_compare_with_data (const void * a, const void * b, void * + _index) +{ + struct index * index = _index; + + return index->compare (* (const void * *) a, * (const void * *) b, + index->compare_data); } -void index_sort (struct index * index, gint (* compare) (const void * *, const - void * *)) +void index_sort_with_data (struct index * index, gint (* compare) + (const void * a, const void * b, void * data), void * data) { - qsort (index->data, index->length, sizeof (void *), (gint (*) (const void *, - const void *)) compare); + index->compare = compare; + index->compare_data = data; + g_qsort_with_data (index->data, index->count, sizeof (void *), + index_compare_with_data, index); + index->compare = NULL; + index->compare_data = NULL; } diff --git a/src/libaudcore/index.h b/src/libaudcore/index.h index e219595..67b1781 100644 --- a/src/libaudcore/index.h +++ b/src/libaudcore/index.h @@ -1,12 +1,12 @@ /* * index.h - * Copyright 2009 John Lindgren + * Copyright 2009-2010 John Lindgren * * This file is part of Audacious. * * Audacious is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software - * Foundation, version 3 of the License. + * Foundation, version 2 or version 3 of the License. * * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR @@ -31,10 +31,19 @@ void index_set (struct index * index, gint at, void * value); void * index_get (struct index * index, gint at); void index_insert (struct index * index, gint at, void * value); void index_append (struct index * index, void * value); +void index_copy_set (struct index * source, gint from, struct index * target, + gint to, gint count); +void index_copy_insert (struct index * source, gint from, struct index * target, + gint to, gint count); +void index_copy_append (struct index * source, gint from, struct index * target, + gint count); void index_merge_insert (struct index * first, gint at, struct index * second); void index_merge_append (struct index * first, struct index * second); -void index_delete (struct index * index, gint at, gint length); -void index_sort (struct index * index, gint (* compare) (const void * *, const - void * *)); +void index_move (struct index * index, gint from, gint to, gint count); +void index_delete (struct index * index, gint at, gint count); +void index_sort (struct index * index, gint (* compare) (const void * a, + const void * b)); +void index_sort_with_data (struct index * index, gint (* compare) + (const void * a, const void * b, void * data), void * data); #endif diff --git a/src/libaudcore/tuple.c b/src/libaudcore/tuple.c index 8d47d49..ef360be 100644 --- a/src/libaudcore/tuple.c +++ b/src/libaudcore/tuple.c @@ -63,6 +63,15 @@ const TupleBasicType tuple_fields[FIELD_LAST] = { { "segment-start", TUPLE_INT }, { "segment-end", TUPLE_INT }, + + { "gain-album-gain", TUPLE_INT }, + { "gain-album-peak", TUPLE_INT }, + { "gain-track-gain", TUPLE_INT }, + { "gain-track-peak", TUPLE_INT }, + { "gain-gain-unit", TUPLE_INT }, + { "gain-peak-unit", TUPLE_INT }, + + { "composer", TUPLE_STRING }, }; @@ -162,7 +171,7 @@ tuple_new(void) Tuple *tuple; TUPLE_LOCK_WRITE(); - + tuple = tuple_new_unlocked(); TUPLE_UNLOCK_WRITE(); @@ -392,7 +401,7 @@ tuple_associate_data(Tuple *tuple, const gint cnfield, const gchar *field, Tuple /** * Associates copy of given string to a field in specified #Tuple. * If field already exists, old value is freed and replaced. - * + * * Desired field can be specified either by key name or if it is * one of basic fields, by #TupleBasicType index. * @@ -424,7 +433,7 @@ tuple_associate_string(Tuple *tuple, const gint nfield, const gchar *field, cons * Associates given string to a field in specified #Tuple. The caller * gives up ownership of the string. If field already exists, old * value is freed and replaced. - * + * * Desired field can be specified either by key name or if it is * one of basic fields, by #TupleBasicType index. * diff --git a/src/libaudcore/tuple.h b/src/libaudcore/tuple.h index 338ebd9..4823cb2 100644 --- a/src/libaudcore/tuple.h +++ b/src/libaudcore/tuple.h @@ -67,6 +67,21 @@ enum { FIELD_SEGMENT_START, FIELD_SEGMENT_END, + /* Preserving replay gain information accurately is a challenge since there + * are several differents formats around. We use an integer fraction, with + * the denominator stored in the *_UNIT fields. For example, if ALBUM_GAIN + * is 512 and GAIN_UNIT is 256, then the album gain is +2 dB. If TRACK_PEAK + * is 787 and PEAK_UNIT is 1000, then the peak volume is 0.787 in a -1.0 to + * 1.0 range. */ + FIELD_GAIN_ALBUM_GAIN, + FIELD_GAIN_ALBUM_PEAK, + FIELD_GAIN_TRACK_GAIN, + FIELD_GAIN_TRACK_PEAK, + FIELD_GAIN_GAIN_UNIT, + FIELD_GAIN_PEAK_UNIT, + + FIELD_COMPOSER, /**< Composer of song, if different than artist. */ + /* Special field, must always be last */ FIELD_LAST }; diff --git a/src/libaudcore/vfs.c b/src/libaudcore/vfs.c index e6d929a..b901d0e 100644 --- a/src/libaudcore/vfs.c +++ b/src/libaudcore/vfs.c @@ -37,14 +37,10 @@ GList *vfs_transports = NULL; /* temporary. -nenolod */ * Registers a #VFSConstructor vtable with the VFS system. * * @param vtable The #VFSConstructor vtable to register. - * @return TRUE on success, FALSE on failure. */ -gboolean -vfs_register_transport(VFSConstructor *vtable) +void vfs_register_transport (VFSConstructor * vtable) { - vfs_transports = g_list_append(vfs_transports, vtable); - - return TRUE; + vfs_transports = g_list_append (vfs_transports, vtable); } static VFSConstructor * @@ -70,7 +66,7 @@ vfs_get_constructor(const gchar *path) /* No transport vtable has been registered, bail. */ if (vtable == NULL) g_warning("Could not open '%s', no transport plugin available.", path); - + return vtable; } @@ -91,7 +87,7 @@ vfs_fopen(const gchar * path, if (path == NULL || mode == NULL || (vtable = vfs_get_constructor(path)) == NULL) return NULL; - + file = vtable->vfs_fopen_impl(path, mode); if (file == NULL) @@ -139,11 +135,7 @@ vfs_fclose(VFSFile * file) * @param file #VFSFile object that represents the VFS stream. * @return The number of elements succesfully read. */ -gsize -vfs_fread(gpointer ptr, - gsize size, - gsize nmemb, - VFSFile * file) +gint64 vfs_fread (void * ptr, gint64 size, gint64 nmemb, VFSFile * file) { if (file == NULL) return 0; @@ -160,11 +152,7 @@ vfs_fread(gpointer ptr, * @param file #VFSFile object that represents the VFS stream. * @return The number of elements succesfully written. */ -gsize -vfs_fwrite(gconstpointer ptr, - gsize size, - gsize nmemb, - VFSFile * file) +gint64 vfs_fwrite (const void * ptr, gint64 size, gint64 nmemb, VFSFile * file) { if (file == NULL) return 0; @@ -218,7 +206,7 @@ vfs_ungetc(gint c, VFSFile *file) */ gint vfs_fseek(VFSFile * file, - glong offset, + gint64 offset, gint whence) { if (file == NULL) @@ -278,13 +266,12 @@ vfs_feof(VFSFile * file) * @param length The length to truncate at. * @return On success, 0. Otherwise, -1. */ -gint -vfs_truncate(VFSFile * file, glong length) +gint vfs_ftruncate (VFSFile * file, gint64 length) { if (file == NULL) return -1; - return file->base->vfs_truncate_impl(file, length); + return file->base->vfs_ftruncate_impl(file, length); } /** @@ -293,7 +280,7 @@ vfs_truncate(VFSFile * file, glong length) * @param file #VFSFile object that represents the VFS stream. * @return On success, the size of the file in bytes. Otherwise, -1. */ -off_t +gint64 vfs_fsize(VFSFile * file) { if (file == NULL) @@ -314,7 +301,7 @@ vfs_get_metadata(VFSFile * file, const gchar * field) { if (file == NULL) return NULL; - + if (file->base->vfs_get_metadata_impl) return file->base->vfs_get_metadata_impl(file, field); return NULL; diff --git a/src/libaudcore/vfs.h b/src/libaudcore/vfs.h index f268550..fc97884 100644 --- a/src/libaudcore/vfs.h +++ b/src/libaudcore/vfs.h @@ -1,6 +1,6 @@ /* * Audacious - * Copyright (c) 2006-2007 Audacious team + * Copyright (c) 2006-2010 Audacious team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,13 +44,13 @@ typedef struct _VFSConstructor VFSConstructor; * similar in purpose as stdio FILE */ struct _VFSFile { - gchar *uri; /**< The URI of the stream */ - gpointer handle; /**< Opaque data used by the transport plugins */ - VFSConstructor *base; /**< The base vtable used for VFS functions */ - gint ref; /**< The amount of references that the VFSFile object has */ + gchar *uri; /**< The URI of the stream */ + gpointer handle; /**< Opaque data used by the transport plugins */ + VFSConstructor *base; /**< The base vtable used for VFS functions */ + gint ref; /**< The amount of references that the VFSFile object has */ }; -/** +/** * @struct _VFSConstructor * #VFSConstructor objects contain the base vtables used for extrapolating * a VFS stream. #VFSConstructor objects should be considered %virtual in @@ -58,103 +58,97 @@ struct _VFSFile { */ struct _VFSConstructor { /** The URI identifier, e.g. "file" would handle "file://" streams. */ - gchar *uri_id; - /** A function pointer which points to a fopen implementation. */ - VFSFile *(*vfs_fopen_impl)(const gchar *path, - const gchar *mode); + gchar * uri_id; + + /** A function pointer which points to a fopen implementation. */ + VFSFile * (* vfs_fopen_impl) (const gchar * filename, const gchar * mode); /** A function pointer which points to a fclose implementation. */ - gint (*vfs_fclose_impl)(VFSFile * file); - /** A function pointer which points to a fread implementation. */ - gsize (*vfs_fread_impl)(gpointer ptr, gsize size, - gsize nmemb, VFSFile *file); + gint (* vfs_fclose_impl) (VFSFile * file); + + /** A function pointer which points to a fread implementation. */ + gint64 (* vfs_fread_impl) (void * ptr, gint64 size, gint64 nmemb, VFSFile * + file); /** A function pointer which points to a fwrite implementation. */ - gsize (*vfs_fwrite_impl)(gconstpointer ptr, gsize size, - gsize nmemb, VFSFile *file); + gint64 (* vfs_fwrite_impl) (const void * ptr, gint64 size, gint64 nmemb, + VFSFile * file); + /** A function pointer which points to a getc implementation. */ - gint (*vfs_getc_impl)(VFSFile *stream); + gint (* vfs_getc_impl) (VFSFile * stream); /** A function pointer which points to an ungetc implementation. */ - gint (*vfs_ungetc_impl)(gint c, VFSFile *stream); + gint (* vfs_ungetc_impl) (gint c, VFSFile * stream); + /** A function pointer which points to a fseek implementation. */ - gint (*vfs_fseek_impl)(VFSFile *file, glong offset, gint whence); - /** function pointer which points to a rewind implementation. */ - void (*vfs_rewind_impl)(VFSFile *file); + gint (* vfs_fseek_impl) (VFSFile * file, gint64 offset, gint whence); + /** function pointer which points to a rewind implementation. */ + void (* vfs_rewind_impl) (VFSFile * file); /** A function pointer which points to a ftell implementation. */ - glong (*vfs_ftell_impl)(VFSFile *file); - /** A function pointer which points to a feof implementation. */ - gboolean (*vfs_feof_impl)(VFSFile *file); - /** A function pointer which points to a ftruncate implementation. */ - gboolean (*vfs_truncate_impl)(VFSFile *file, glong length); - /** A function pointer which points to a fsize implementation. */ - off_t (*vfs_fsize_impl)(VFSFile *file); - /** A function pointer which points to a (stream) metadata fetching implementation. */ - gchar *(*vfs_get_metadata_impl)(VFSFile *file, const gchar * field); + gint64 (* vfs_ftell_impl) (VFSFile * file); + /** A function pointer which points to a feof implementation. */ + gboolean (* vfs_feof_impl) (VFSFile * file); + /** A function pointer which points to a ftruncate implementation. */ + gint (* vfs_ftruncate_impl) (VFSFile * file, gint64 length); + /** A function pointer which points to a fsize implementation. */ + gint64 (* vfs_fsize_impl) (VFSFile * file); + + /** A function pointer which points to a (stream) metadata fetching implementation. */ + gchar * (* vfs_get_metadata_impl) (VFSFile * file, const gchar * field); }; - -extern VFSFile * vfs_fopen(const gchar * path, - const gchar * mode); -extern gint vfs_fclose(VFSFile * file); - -extern VFSFile * vfs_dup(VFSFile *in); - -extern gsize vfs_fread(gpointer ptr, - gsize size, - gsize nmemb, - VFSFile * file); -extern gsize vfs_fwrite(gconstpointer ptr, - gsize size, - gsize nmemb, - VFSFile *file); - -extern gint vfs_getc(VFSFile *stream); -extern gint vfs_ungetc(gint c, - VFSFile *stream); -extern gchar *vfs_fgets(gchar *s, - gint n, - VFSFile *stream); - -extern gint vfs_fseek(VFSFile * file, - glong offset, - gint whence); -extern void vfs_rewind(VFSFile * file); -extern glong vfs_ftell(VFSFile * file); -extern gboolean vfs_feof(VFSFile * file); - -extern gboolean vfs_file_test(const gchar * path, - GFileTest test); - -extern gboolean vfs_is_writeable(const gchar * path); - -extern gboolean vfs_truncate(VFSFile * file, glong length); - -extern off_t vfs_fsize(VFSFile * file); - -extern gchar *vfs_get_metadata(VFSFile * file, const gchar * field); - -extern gint vfs_fprintf(VFSFile *stream, gchar const *format, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); - -extern gboolean vfs_register_transport(VFSConstructor *vtable); - -extern void vfs_file_get_contents(const gchar *filename, gchar **buf, gsize *size); - -extern gboolean vfs_is_remote(const gchar * path); - -extern gboolean vfs_is_streaming(VFSFile *file); - -extern gboolean vfs_fget_le16(guint16 *value, VFSFile *stream); -extern gboolean vfs_fget_le32(guint32 *value, VFSFile *stream); -extern gboolean vfs_fget_le64(guint64 *value, VFSFile *stream); -extern gboolean vfs_fget_be16(guint16 *value, VFSFile *stream); -extern gboolean vfs_fget_be32(guint32 *value, VFSFile *stream); -extern gboolean vfs_fget_be64(guint64 *value, VFSFile *stream); - -extern gboolean vfs_fput_le16(guint16 value, VFSFile *stream); -extern gboolean vfs_fput_le32(guint32 value, VFSFile *stream); -extern gboolean vfs_fput_le64(guint64 value, VFSFile *stream); -extern gboolean vfs_fput_be16(guint16 value, VFSFile *stream); -extern gboolean vfs_fput_be32(guint32 value, VFSFile *stream); -extern gboolean vfs_fput_be64(guint64 value, VFSFile *stream); +#ifdef __GNUC__ +#define WARN_RETURN __attribute__ ((warn_unused_result)) +#else +#define WARN_RETURN +#endif + +VFSFile * vfs_fopen (const gchar * path, const gchar * mode) WARN_RETURN; +VFSFile * vfs_dup (VFSFile * in) WARN_RETURN; +gint vfs_fclose (VFSFile * file); + +gint64 vfs_fread (void * ptr, gint64 size, gint64 nmemb, VFSFile * file) + WARN_RETURN; +gint64 vfs_fwrite (const void * ptr, gint64 size, gint64 nmemb, VFSFile * file) + WARN_RETURN; + +gint vfs_getc (VFSFile * stream) WARN_RETURN; +gint vfs_ungetc (gint c, VFSFile * stream) WARN_RETURN; +gchar * vfs_fgets (gchar * s, gint n, VFSFile * stream) WARN_RETURN; +gboolean vfs_feof (VFSFile * file) WARN_RETURN; +gint vfs_fprintf (VFSFile * stream, gchar const * format, ...) __attribute__ + ((__format__ (__printf__, 2, 3))); + +gint vfs_fseek (VFSFile * file, gint64 offset, gint whence) WARN_RETURN; +void vfs_rewind (VFSFile * file); +glong vfs_ftell (VFSFile * file) WARN_RETURN; +gint64 vfs_fsize (VFSFile * file) WARN_RETURN; +gint vfs_ftruncate (VFSFile * file, gint64 length) WARN_RETURN; + +gboolean vfs_fget_le16 (guint16 * value, VFSFile * stream) WARN_RETURN; +gboolean vfs_fget_le32 (guint32 * value, VFSFile * stream) WARN_RETURN; +gboolean vfs_fget_le64 (guint64 * value, VFSFile * stream) WARN_RETURN; +gboolean vfs_fget_be16 (guint16 * value, VFSFile * stream) WARN_RETURN; +gboolean vfs_fget_be32 (guint32 * value, VFSFile * stream) WARN_RETURN; +gboolean vfs_fget_be64 (guint64 * value, VFSFile * stream) WARN_RETURN; + +gboolean vfs_fput_le16 (guint16 value, VFSFile * stream) WARN_RETURN; +gboolean vfs_fput_le32 (guint32 value, VFSFile * stream) WARN_RETURN; +gboolean vfs_fput_le64 (guint64 value, VFSFile * stream) WARN_RETURN; +gboolean vfs_fput_be16 (guint16 value, VFSFile * stream) WARN_RETURN; +gboolean vfs_fput_be32 (guint32 value, VFSFile * stream) WARN_RETURN; +gboolean vfs_fput_be64 (guint64 value, VFSFile * stream) WARN_RETURN; + +gboolean vfs_is_streaming (VFSFile * file) WARN_RETURN; +gchar * vfs_get_metadata (VFSFile * file, const gchar * field) WARN_RETURN; + +gboolean vfs_file_test (const gchar * path, GFileTest test) WARN_RETURN; +gboolean vfs_is_writeable (const gchar * path) WARN_RETURN; +gboolean vfs_is_remote (const gchar * path) WARN_RETURN; + +void vfs_file_get_contents (const gchar * filename, guchar * * buf, gint64 * + size); + +void vfs_register_transport (VFSConstructor * vtable); + +#undef WARN_RETURN G_END_DECLS diff --git a/src/libaudcore/vfs_buffer.c b/src/libaudcore/vfs_buffer.c index 322f5a0..ef2ad8f 100644 --- a/src/libaudcore/vfs_buffer.c +++ b/src/libaudcore/vfs_buffer.c @@ -40,11 +40,8 @@ buffer_vfs_fclose_impl(VFSFile * file) return 0; } -static gsize -buffer_vfs_fread_impl(gpointer i_ptr, - gsize size, - gsize nmemb, - VFSFile * file) +static gint64 buffer_vfs_fread_impl (void * i_ptr, gint64 size, gint64 nmemb, + VFSFile * file) { VFSBuffer *handle; guchar *i; @@ -56,7 +53,7 @@ buffer_vfs_fread_impl(gpointer i_ptr, handle = (VFSBuffer *) file->handle; - for (i = ptr; (gsize) (i - ptr) < nmemb * size && + for (i = ptr; (gsize) (i - ptr) < nmemb * size && (gsize) (i - ptr) <= handle->size; i++, handle->iter++) { @@ -67,11 +64,8 @@ buffer_vfs_fread_impl(gpointer i_ptr, return (read / size); } -static gsize -buffer_vfs_fwrite_impl(gconstpointer i_ptr, - gsize size, - gsize nmemb, - VFSFile * file) +static gint64 buffer_vfs_fwrite_impl (const void * i_ptr, gint64 size, gint64 + nmemb, VFSFile * file) { VFSBuffer *handle; const guchar *i; @@ -233,7 +227,7 @@ vfs_buffer_new(gpointer data, gsize size) g_free(handle); return NULL; } - + buffer->data = data; buffer->iter = data; buffer->end = (guchar *) data + size; diff --git a/src/libaudcore/vfs_buffered_file.c b/src/libaudcore/vfs_buffered_file.c index 285bfb3..f34a0e9 100644 --- a/src/libaudcore/vfs_buffered_file.c +++ b/src/libaudcore/vfs_buffered_file.c @@ -50,19 +50,16 @@ buffered_file_vfs_fclose_impl(VFSFile * file) return 0; } -gsize -buffered_file_vfs_fread_impl(gpointer i_ptr, - gsize size, - gsize nmemb, - VFSFile * file) +gint64 buffered_file_vfs_fread_impl (void * i_ptr, gint64 size, gint64 nmemb, + VFSFile * file) { VFSBufferedFile *handle = (VFSBufferedFile *) file->handle; - /* is this request within the buffered area, or should we switch to + /* is this request within the buffered area, or should we switch to * an FD? --nenolod */ - if (handle->which == FALSE && - (vfs_ftell(handle->buffer)) + (size * nmemb) > + if (handle->which == FALSE && + (vfs_ftell(handle->buffer)) + (size * nmemb) > ((VFSBuffer *) handle->buffer->handle)->size) { vfs_fseek(handle->fd, vfs_ftell(handle->buffer), SEEK_SET); @@ -72,11 +69,8 @@ buffered_file_vfs_fread_impl(gpointer i_ptr, return vfs_fread(i_ptr, size, nmemb, handle->which == TRUE ? handle->fd : handle->buffer); } -gsize -buffered_file_vfs_fwrite_impl(gconstpointer i_ptr, - gsize size, - gsize nmemb, - VFSFile * file) +gint64 buffered_file_vfs_fwrite_impl (const void * i_ptr, gint64 size, gint64 + nmemb, VFSFile * file) { VFSBufferedFile *handle = (VFSBufferedFile *) file->handle; @@ -88,7 +82,7 @@ buffered_file_vfs_getc_impl(VFSFile *stream) { VFSBufferedFile *handle = (VFSBufferedFile *) stream->handle; - /* is this request within the buffered area, or should we switch to + /* is this request within the buffered area, or should we switch to * an FD? --nenolod */ if ((vfs_ftell(handle->buffer)) + 1 > @@ -127,7 +121,7 @@ buffered_file_vfs_fseek_impl(VFSFile * file, { handle->which = TRUE; vfs_fseek(handle->fd, offset, whence); - } + } break; case SEEK_SET: default: diff --git a/src/libaudcore/vfs_common.c b/src/libaudcore/vfs_common.c index a9728d7..fcee8b9 100644 --- a/src/libaudcore/vfs_common.c +++ b/src/libaudcore/vfs_common.c @@ -137,13 +137,13 @@ gint vfs_fprintf(VFSFile *stream, gchar const *format, ...) * @param size Pointer to gsize variable that will hold the amount of * read data e.g. filesize. */ -void -vfs_file_get_contents(const gchar *filename, gchar **buf, gsize *size) +void vfs_file_get_contents (const gchar * filename, guchar * * buf, gint64 * + size) { VFSFile *fd; gsize filled_size = 0, buf_size = 4096; - gchar *ptr; - + guchar * ptr; + if ((fd = vfs_fopen(filename, "rb")) == NULL) return; @@ -171,26 +171,26 @@ vfs_file_get_contents(const gchar *filename, gchar **buf, gsize *size) while (TRUE) { gsize read_size = vfs_fread(ptr, 1, buf_size - filled_size, fd); if (read_size == 0) break; - + filled_size += read_size; ptr += read_size; - + if (filled_size == buf_size) { buf_size += 4096; - + *buf = g_realloc(*buf, buf_size); - + if (*buf == NULL) goto close_handle; - + ptr = *buf + filled_size; } } *size = filled_size; - + close_handle: - vfs_fclose(fd); + vfs_fclose(fd); } diff --git a/src/libaudgui/Makefile b/src/libaudgui/Makefile index 2cbae8f..9c88651 100644 --- a/src/libaudgui/Makefile +++ b/src/libaudgui/Makefile @@ -2,7 +2,12 @@ LIB = ${LIB_PREFIX}audgui${LIB_SUFFIX} LIB_MAJOR = 1 LIB_MINOR = 0 -SRCS = effects-menu.c \ +SRCS = confirm.c \ + effects-menu.c \ + infopopup.c \ + infowin.c \ + init.c \ + library-store.c \ ui_gtk.c \ ui_fileopener.c \ ui_urlopener.c \ @@ -10,7 +15,9 @@ SRCS = effects-menu.c \ ui_jumptotrack_cache.c \ icons-stock.c \ ui_about.c \ - ui_credits.c + ui_credits.c \ + ui_playlist_manager.c \ + util.c INCLUDES = libaudgui.h \ libaudgui-gtk.h diff --git a/src/libaudgui/confirm.c b/src/libaudgui/confirm.c new file mode 100644 index 0000000..ee64d1e --- /dev/null +++ b/src/libaudgui/confirm.c @@ -0,0 +1,98 @@ +/* + * libaudgui/confirm.c + * Copyright 2010 John Lindgren + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 or version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#include <audacious/i18n.h> +#include <audacious/plugin.h> + +#include "libaudgui-gtk.h" + +static void confirm_delete_cb (GtkButton * button, void * data) +{ + if (GPOINTER_TO_INT (data) < aud_playlist_count ()) + aud_playlist_delete (GPOINTER_TO_INT (data)); +} + +void audgui_confirm_playlist_delete (gint playlist) +{ + GtkWidget * window, * vbox, * hbox, * label, * button; + gchar * message; + + if (aud_cfg->no_confirm_playlist_delete) + { + aud_playlist_delete (playlist); + return; + } + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_type_hint ((GtkWindow *) window, + GDK_WINDOW_TYPE_HINT_DIALOG); + gtk_window_set_resizable ((GtkWindow *) window, FALSE); + gtk_container_set_border_width ((GtkContainer *) window, 6); + audgui_destroy_on_escape (window); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_container_add ((GtkContainer *) window, vbox); + + hbox = gtk_hbox_new (FALSE, 6); + gtk_box_pack_start ((GtkBox *) vbox, hbox, FALSE, FALSE, 0); + + gtk_box_pack_start ((GtkBox *) hbox, gtk_image_new_from_stock + (GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG), FALSE, FALSE, 0); + + message = g_strdup_printf (_("Are you sure you want to close %s? If you " + "do, any changes made since the playlist was exported will be lost."), + aud_playlist_get_title (playlist)); + label = gtk_label_new (message); + g_free (message); + gtk_label_set_line_wrap ((GtkLabel *) label, TRUE); + gtk_widget_set_size_request (label, 320, -1); + gtk_box_pack_start ((GtkBox *) hbox, label, TRUE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 6); + gtk_box_pack_start ((GtkBox *) vbox, hbox, FALSE, FALSE, 0); + + button = gtk_check_button_new_with_mnemonic (_("_Don't show this message " + "again")); + gtk_box_pack_start ((GtkBox *) hbox, button, FALSE, FALSE, 0); + audgui_connect_check_box (button, & aud_cfg->no_confirm_playlist_delete); + + hbox = gtk_hbox_new (FALSE, 6); + gtk_box_pack_start ((GtkBox *) vbox, hbox, FALSE, FALSE, 0); + + button = gtk_button_new_from_stock (GTK_STOCK_NO); + gtk_box_pack_end ((GtkBox *) hbox, button, FALSE, FALSE, 0); + g_signal_connect_swapped (button, "clicked", (GCallback) + gtk_widget_destroy, window); + + button = gtk_button_new_from_stock (GTK_STOCK_YES); + gtk_box_pack_end ((GtkBox *) hbox, button, FALSE, FALSE, 0); +#if GTK_CHECK_VERSION (2, 18, 0) + gtk_widget_set_can_default (button, TRUE); +#endif + gtk_widget_grab_default (button); + gtk_widget_grab_focus (button); + g_signal_connect ((GObject *) button, "clicked", (GCallback) + confirm_delete_cb, GINT_TO_POINTER (playlist)); + g_signal_connect_swapped ((GObject *) button, "clicked", (GCallback) + gtk_widget_destroy, window); + + gtk_widget_show_all (window); +} diff --git a/src/libaudgui/infopopup.c b/src/libaudgui/infopopup.c new file mode 100644 index 0000000..b045d4c --- /dev/null +++ b/src/libaudgui/infopopup.c @@ -0,0 +1,428 @@ +/* + * libaudgui/infopopup.c + * Copyright 2006 William Pitcock, Tony Vroon, George Averill, Giacomo Lozito, + * Derek Pomery and Yoshiki Yazawa. + * Copyright 2010 John Lindgren + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 or version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#include <gtk/gtk.h> +#include <string.h> + +#include <audacious/i18n.h> +#include <audacious/plugin.h> + +#include "libaudgui.h" +#include "libaudgui-gtk.h" + +#define DEFAULT_ARTWORK DATA_DIR "/images/audio.png" + +static GtkWidget * infopopup = NULL; + +static void infopopup_entry_set_text (const gchar * entry_name, const gchar * + text) +{ + GtkWidget * widget = g_object_get_data ((GObject *) infopopup, entry_name); + + g_return_if_fail (widget != NULL); + gtk_label_set_text ((GtkLabel *) widget, text); +} + +static void infopopup_entry_set_image (const gchar * entry_name, const gchar * + text) +{ + GtkWidget * widget = g_object_get_data ((GObject *) infopopup, entry_name); + GdkPixbuf * pixbuf; + gint width, height; + gfloat aspect; + + pixbuf = gdk_pixbuf_new_from_file (text, NULL); + g_return_if_fail (pixbuf != NULL); + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + + if (strcmp (DEFAULT_ARTWORK, text)) + { + GdkPixbuf * pixbuf2; + + aspect = height / (gfloat) width; + + if (aspect > 1) + { + height = aud_cfg->filepopup_pixelsize * aspect; + width = aud_cfg->filepopup_pixelsize; + } + else + { + height = aud_cfg->filepopup_pixelsize; + width = aud_cfg->filepopup_pixelsize / aspect; + } + + pixbuf2 = gdk_pixbuf_scale_simple (pixbuf, width, height, + GDK_INTERP_BILINEAR); + g_object_unref (pixbuf); + pixbuf = pixbuf2; + } + + gtk_image_set_from_pixbuf ((GtkImage *) widget, pixbuf); + g_object_unref (pixbuf); +} + +static gboolean infopopup_progress_cb (void * unused) +{ + GtkWidget * progressbar = g_object_get_data ((GObject *) infopopup, + "progressbar"); + gchar * tooltip_file = g_object_get_data ((GObject *) infopopup, "file"); + gint length = GPOINTER_TO_INT (g_object_get_data ((GObject *) infopopup, + "length")); + gint playlist, entry, time; + const gchar * filename; + gchar * progress_time; + + g_return_val_if_fail (tooltip_file != NULL, FALSE); + g_return_val_if_fail (length > 0, FALSE); + + if (! aud_cfg->filepopup_showprogressbar || ! audacious_drct_get_playing ()) + goto HIDE; + + playlist = aud_playlist_get_playing (); + + if (playlist == -1) + goto HIDE; + + entry = aud_playlist_get_position (playlist); + + if (entry == -1) + goto HIDE; + + filename = aud_playlist_entry_get_filename (playlist, entry); + + if (strcmp (filename, tooltip_file)) + goto HIDE; + + time = audacious_drct_get_time (); + gtk_progress_bar_set_fraction ((GtkProgressBar *) progressbar, time / + (gfloat) length); + progress_time = g_strdup_printf ("%d:%02d", time / 60000, (time / 1000) % 60); + gtk_progress_bar_set_text ((GtkProgressBar *) progressbar, progress_time); + g_free (progress_time); + + gtk_widget_show (progressbar); + return TRUE; + +HIDE: + /* tooltip opened, but song is not the same, or playback is stopped */ + gtk_widget_hide (progressbar); + return TRUE; +} + +static void infopopup_progress_init (void) +{ + g_object_set_data ((GObject *) infopopup, "progress_sid", GINT_TO_POINTER + (0)); +} + +static void infopopup_progress_start (void) +{ + gint sid = g_timeout_add (500, (GSourceFunc) infopopup_progress_cb, NULL); + + g_object_set_data ((GObject *) infopopup, "progress_sid", GINT_TO_POINTER + (sid)); +} + +static void infopopup_progress_stop (void) +{ + gint sid = GPOINTER_TO_INT (g_object_get_data ((GObject *) infopopup, + "progress_sid")); + + if (! sid) + return; + + g_source_remove (sid); + g_object_set_data ((GObject *) infopopup, "progress_sid", GINT_TO_POINTER + (0)); +} + +static void infopopup_add_category (GtkWidget * infopopup_data_table, + const gchar * category, const gchar * header_data, const gchar * label_data, + gint position) +{ + GtkWidget * infopopup_data_info_header = gtk_label_new (""); + GtkWidget * infopopup_data_info_label = gtk_label_new (""); + gchar * markup; + + gtk_misc_set_alignment ((GtkMisc *) infopopup_data_info_header, 0, 0.5); + gtk_misc_set_alignment ((GtkMisc *) infopopup_data_info_label, 0, 0.5); + gtk_misc_set_padding ((GtkMisc *) infopopup_data_info_header, 0, 3); + gtk_misc_set_padding ((GtkMisc *) infopopup_data_info_label, 0, 3); + + markup = g_markup_printf_escaped ("<span style=\"italic\">%s</span>", + category); + gtk_label_set_markup ((GtkLabel *) infopopup_data_info_header, markup); + g_free (markup); + + g_object_set_data ((GObject *) infopopup, header_data, + infopopup_data_info_header); + g_object_set_data ((GObject *) infopopup, label_data, + infopopup_data_info_label); + gtk_table_attach ((GtkTable *) infopopup_data_table, + infopopup_data_info_header, 0, 1, position, position + 1, GTK_FILL, 0, 0, 0); + gtk_table_attach ((GtkTable *) infopopup_data_table, + infopopup_data_info_label, 1, 2, position, position + 1, GTK_FILL, 0, 0, 0); +} + +static void infopopup_create (void) +{ + GtkWidget * infopopup_hbox; + GtkWidget * infopopup_data_image; + GtkWidget * infopopup_data_table; + GtkWidget * infopopup_progress; + + infopopup = gtk_window_new (GTK_WINDOW_POPUP); + gtk_window_set_type_hint ((GtkWindow *) infopopup, + GDK_WINDOW_TYPE_HINT_TOOLTIP); + gtk_window_set_decorated ((GtkWindow *) infopopup, FALSE); + gtk_container_set_border_width ((GtkContainer *) infopopup, 6); + + infopopup_hbox = gtk_hbox_new (FALSE, 0); + gtk_container_add ((GtkContainer *) infopopup, infopopup_hbox); + + infopopup_data_image = gtk_image_new (); + gtk_misc_set_alignment ((GtkMisc *) infopopup_data_image, 0.5, 0); + gtk_image_set_from_file ((GtkImage *) infopopup_data_image, DEFAULT_ARTWORK); + + g_object_set_data ((GObject *) infopopup, "image_artwork", + infopopup_data_image); + g_object_set_data ((GObject *) infopopup, "last_artwork", NULL); + gtk_box_pack_start ((GtkBox *) infopopup_hbox, infopopup_data_image, FALSE, + FALSE, 0); + + gtk_box_pack_start ((GtkBox *) infopopup_hbox, gtk_vseparator_new (), FALSE, + FALSE, 6); + + infopopup_data_table = gtk_table_new (8, 2, FALSE); + gtk_table_set_row_spacings ((GtkTable *) infopopup_data_table, 0); + gtk_table_set_col_spacings ((GtkTable *) infopopup_data_table, 6); + gtk_box_pack_start ((GtkBox *) infopopup_hbox, infopopup_data_table, TRUE, + TRUE, 0); + + infopopup_add_category (infopopup_data_table, _("Title"), "header_title", + "label_title", 0); + infopopup_add_category (infopopup_data_table, _("Artist"), "header_artist", + "label_artist", 1); + infopopup_add_category (infopopup_data_table, _("Album"), "header_album", + "label_album", 2); + infopopup_add_category (infopopup_data_table, _("Genre"), "header_genre", + "label_genre", 3); + infopopup_add_category (infopopup_data_table, _("Year"), "header_year", + "label_year", 4); + infopopup_add_category (infopopup_data_table, _("Track Number"), + "header_tracknum", "label_tracknum", 5); + infopopup_add_category (infopopup_data_table, _("Track Length"), + "header_tracklen", "label_tracklen", 6); + + gtk_table_set_row_spacing ((GtkTable *) infopopup_data_table, 6, 6); + + /* track progress */ + infopopup_progress = gtk_progress_bar_new (); + gtk_progress_bar_set_orientation ((GtkProgressBar *) infopopup_progress, + GTK_PROGRESS_LEFT_TO_RIGHT); + gtk_progress_bar_set_text ((GtkProgressBar *) infopopup_progress, ""); + gtk_table_attach ((GtkTable *) infopopup_data_table, infopopup_progress, 0, + 2, 7, 8, GTK_FILL, 0, 0, 0); + g_object_set_data ((GObject *) infopopup, "file", NULL); + g_object_set_data ((GObject *) infopopup, "progressbar", infopopup_progress); + infopopup_progress_init (); + + /* do not show the track progress */ + gtk_widget_set_no_show_all (infopopup_progress, TRUE); + gtk_widget_show_all (infopopup_hbox); +} + +#if 0 +static void infopopup_destroy (void) +{ + infopopup_progress_stop (infopopup); + g_free (g_object_get_data ((GObject *) infopopup, "last_artwork")); + gtk_widget_destroy (infopopup); +} +#endif + +static void infopopup_update_data (const gchar * text, const gchar * label_data, + const gchar * header_data) +{ + if (text != NULL) + { + infopopup_entry_set_text (label_data, text); + gtk_widget_show ((GtkWidget *) g_object_get_data ((GObject *) infopopup, + header_data)); + gtk_widget_show ((GtkWidget *) g_object_get_data ((GObject *) infopopup, + label_data)); + } + else + { + gtk_widget_hide ((GtkWidget *) g_object_get_data ((GObject *) infopopup, + header_data)); + gtk_widget_hide ((GtkWidget *) g_object_get_data ((GObject *) infopopup, + label_data)); + } +} + +static void infopopup_clear (void) +{ + infopopup_progress_stop (); + + infopopup_entry_set_text ("label_title", ""); + infopopup_entry_set_text ("label_artist", ""); + infopopup_entry_set_text ("label_album", ""); + infopopup_entry_set_text ("label_genre", ""); + infopopup_entry_set_text ("label_tracknum", ""); + infopopup_entry_set_text ("label_year", ""); + infopopup_entry_set_text ("label_tracklen", ""); + + gtk_window_resize ((GtkWindow *) infopopup, 1, 1); +} + +static void infopopup_show (const gchar * filename, Tuple * tuple, const gchar * + title) +{ + gint x, y, h, w; + gchar * last_artwork; + gint length, value; + gchar * tmp, * markup; + + if (infopopup == NULL) + infopopup_create (); + else + infopopup_clear (); + + g_free (g_object_get_data ((GObject *) infopopup, "file")); + g_object_set_data ((GObject *) infopopup, "file", g_strdup (filename)); + + markup = g_markup_printf_escaped ("<span style=\"italic\">%s</span>", + _("Title")); + gtk_label_set_markup ((GtkLabel *) g_object_get_data ((GObject *) infopopup, + "header_title"), markup); + g_free (markup); + infopopup_entry_set_text ("label_title", title); + + infopopup_update_data (tuple_get_string (tuple, FIELD_ARTIST, NULL), + "label_artist", "header_artist"); + infopopup_update_data (tuple_get_string (tuple, FIELD_ALBUM, NULL), + "label_album", "header_album"); + infopopup_update_data (tuple_get_string (tuple, FIELD_GENRE, NULL), + "label_genre", "header_genre"); + + length = tuple_get_int (tuple, FIELD_LENGTH, NULL); + tmp = (length > 0) ? g_strdup_printf ("%d:%02d", length / 60000, length / + 1000 % 60) : NULL; + infopopup_update_data (tmp, "label_tracklen", "header_tracklen"); + g_free (tmp); + + g_object_set_data ((GObject *) infopopup, "length" , GINT_TO_POINTER (length)); + + value = tuple_get_int (tuple, FIELD_YEAR, NULL); + tmp = (value > 0) ? g_strdup_printf ("%d", value) : NULL; + infopopup_update_data (tmp, "label_year", "header_year"); + g_free (tmp); + + value = tuple_get_int (tuple, FIELD_TRACK_NUMBER, NULL); + tmp = (value > 0) ? g_strdup_printf ("%d", value) : NULL; + infopopup_update_data (tmp, "label_tracknum", "header_tracknum"); + g_free (tmp); + + last_artwork = g_object_get_data ((GObject *) infopopup, "last_artwork"); + tmp = aud_get_associated_image_file (filename); + + if (tmp == NULL) + tmp = g_strdup (DEFAULT_ARTWORK); + + if (last_artwork == NULL || strcmp (tmp, last_artwork)) + { + infopopup_entry_set_image ("image_artwork", tmp); + g_free (last_artwork); + g_object_set_data ((GObject *) infopopup, "last_artwork", tmp); + } + else + g_free (tmp); + + /* start a timer that updates a progress bar if the tooltip + is shown for the song that is being currently played */ + if (length > 0) + { + infopopup_progress_start (); + /* immediately run the callback once to update progressbar status */ + infopopup_progress_cb (NULL); + } + + gdk_window_get_pointer (gdk_get_default_root_window (), & x, & y, NULL); + gtk_window_get_size ((GtkWindow *) infopopup, & w, & h); + + /* If we show the popup right under the cursor, the underlying window gets + * a "leave-notify-event" and immediately hides the popup again. So, we + * offset the popup slightly. */ + if (x + w > gdk_screen_width ()) + x -= w + 3; + else + x += 3; + + if (y + h > gdk_screen_height ()) + y -= h + 3; + else + y += 3; + + gtk_window_move ((GtkWindow *) infopopup, x, y); + gtk_widget_show (infopopup); +} + +void audgui_infopopup_show (gint playlist, gint entry) +{ + const gchar * filename = aud_playlist_entry_get_filename (playlist, entry); + Tuple * tuple = (Tuple *) aud_playlist_entry_get_tuple (playlist, entry); + + g_return_if_fail (filename != NULL); + + if (tuple == NULL) /* FIXME: show an error popup if this happens */ + return; + + infopopup_show (filename, tuple, aud_playlist_entry_get_title (playlist, + entry)); +} + +void audgui_infopopup_show_current (void) +{ + gint playlist = aud_playlist_get_playing (); + gint position; + + if (playlist == -1) + playlist = aud_playlist_get_active (); + + position = aud_playlist_get_position (playlist); + + if (position == -1) + return; + + audgui_infopopup_show (playlist, position); +} + +void audgui_infopopup_hide (void) +{ + infopopup_progress_stop (); + gtk_widget_hide (infopopup); +} diff --git a/src/libaudgui/infowin.c b/src/libaudgui/infowin.c new file mode 100644 index 0000000..ef58480 --- /dev/null +++ b/src/libaudgui/infowin.c @@ -0,0 +1,912 @@ +/* + * libaudgui/infowin.c + * Copyright 2006 William Pitcock, Tony Vroon, George Averill, Giacomo Lozito, + * Derek Pomery and Yoshiki Yazawa. + * Copyright 2008 Eugene Zagidullin + * Copyright 2010 John Lindgren + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 or version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#include <gtk/gtk.h> +#include <stdarg.h> + +#include <audacious/i18n.h> +#include <audacious/plugin.h> +#include <libaudcore/audstrings.h> + +#include "libaudgui.h" +#include "libaudgui-gtk.h" + +#define STATUS_TIMEOUT 3000 + +static GtkWidget * infowin = NULL; + +static GtkWidget * location_text; +static GtkWidget * entry_title; +static GtkWidget * entry_artist; +static GtkWidget * entry_album; +static GtkWidget * entry_comment; +static GtkWidget * entry_year; +static GtkWidget * entry_track; +static GtkWidget * entry_genre; + +static GtkWidget * image_artwork; + +static GtkWidget * image_fileicon; +static GtkWidget * label_format_name; +static GtkWidget * label_quality; +static GtkWidget * label_bitrate; +static GtkWidget * btn_apply; +static GtkWidget * label_mini_status; +static GtkWidget * arrow_rawdata; +static GtkWidget * treeview_rawdata; + +enum +{ + RAWDATA_KEY, + RAWDATA_VALUE, + RAWDATA_N_COLS +}; + +static gchar * current_file = NULL; +static InputPlugin * current_decoder = NULL; +static gboolean can_write = FALSE, something_changed = FALSE; + +static const gchar * genre_table[] = +{ + N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"), + N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"), + N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"), + N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"), + N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"), + N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"), + N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"), + N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"), + N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"), + N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("AlternRock"), + N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"), + N_("Meditative"), N_("Instrumental Pop"), + N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"), + N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"), + N_("Pop-Folk"), N_("Eurodance"), N_("Dream"), + N_("Southern Rock"), N_("Comedy"), N_("Cult"), + N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"), + N_("Pop/Funk"), N_("Jungle"), N_("Native American"), + N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"), + N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"), + N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"), + N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"), + N_("Folk/Rock"), N_("National Folk"), N_("Swing"), + N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"), + N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"), + N_("Gothic Rock"), N_("Progressive Rock"), + N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"), + N_("Big Band"), N_("Chorus"), N_("Easy Listening"), + N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"), + N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"), + N_("Booty Bass"), N_("Primus"), N_("Porn Groove"), + N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"), + N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"), + N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"), + N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"), + N_("Euro-House"), N_("Dance Hall"), N_("Goa"), + N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"), + N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"), + N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"), + N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"), + N_("Contemporary Christian"), N_("Christian Rock"), + N_("Merengue"), N_("Salsa"), N_("Thrash Metal"), + N_("Anime"), N_("JPop"), N_("Synthpop") +}; + +static GList * genre_list = NULL; + +static void set_entry_str_from_field (GtkWidget * widget, Tuple * tuple, + gint fieldn, gboolean editable) +{ + const gchar * text = tuple_get_string (tuple, fieldn, NULL); + + gtk_entry_set_text ((GtkEntry *) widget, text != NULL ? text : ""); + gtk_editable_set_editable ((GtkEditable *) widget, editable); +} + +static void set_entry_int_from_field (GtkWidget * widget, Tuple * tuple, gint + fieldn, gboolean editable) +{ + gchar scratch[32]; + + if (tuple_get_value_type (tuple, fieldn, NULL) == TUPLE_INT) + snprintf (scratch, sizeof scratch, "%d", tuple_get_int (tuple, fieldn, + NULL)); + else + scratch[0] = 0; + + gtk_entry_set_text ((GtkEntry *) widget, scratch); + gtk_editable_set_editable ((GtkEditable *) widget, editable); +} + +static void set_field_str_from_entry (Tuple * tuple, gint fieldn, GtkWidget * + widget) +{ + const gchar * text = gtk_entry_get_text ((GtkEntry *) widget); + + if (text[0]) + tuple_associate_string (tuple, fieldn, NULL, text); + else + tuple_disassociate (tuple, fieldn, NULL); +} + +static void set_field_int_from_entry (Tuple * tuple, gint fieldn, GtkWidget * + widget) +{ + const gchar * text = gtk_entry_get_text ((GtkEntry *) widget); + + if (text[0]) + tuple_associate_int (tuple, fieldn, NULL, atoi (text)); + else + tuple_disassociate (tuple, fieldn, NULL); +} + +static void infowin_label_set_text (GtkWidget * widget, const gchar * text) +{ + gchar * tmp; + + if (text != NULL) + { + tmp = g_strdup_printf("<span size=\"small\">%s</span>", text); + gtk_label_set_text ((GtkLabel *) widget, tmp); + g_free (tmp); + } + else + gtk_label_set_text ((GtkLabel *) widget, + _("<span size=\"small\">n/a</span>")); + + gtk_label_set_use_markup ((GtkLabel *) widget, TRUE); +} + +static void infowin_entry_set_image (GtkWidget * widget, const char * text) +{ + GdkPixbuf * pixbuf; + + pixbuf = gdk_pixbuf_new_from_file (text, NULL); + g_return_if_fail (pixbuf != NULL); + + if (strcmp (DATA_DIR "/images/audio.png", text)) + audgui_pixbuf_scale_within (& pixbuf, aud_cfg->filepopup_pixelsize); + + gtk_image_set_from_pixbuf ((GtkImage *) widget, pixbuf); + g_object_unref (pixbuf); +} + +static void clear_infowin (void) +{ + gtk_entry_set_text ((GtkEntry *) entry_title, ""); + gtk_entry_set_text ((GtkEntry *) entry_artist, ""); + gtk_entry_set_text ((GtkEntry *) entry_album, ""); + gtk_entry_set_text ((GtkEntry *) entry_comment, ""); + gtk_entry_set_text ((GtkEntry *) gtk_bin_get_child ((GtkBin *) entry_genre), + ""); + gtk_entry_set_text ((GtkEntry *) entry_year, ""); + gtk_entry_set_text ((GtkEntry *) entry_track, ""); + + infowin_label_set_text (label_format_name, NULL); + infowin_label_set_text (label_quality, NULL); + infowin_label_set_text (label_bitrate, NULL); + + gtk_label_set_text ((GtkLabel *) label_mini_status, + "<span size=\"small\"></span>"); + gtk_label_set_use_markup ((GtkLabel *) label_mini_status, TRUE); + + g_free (current_file); + current_file = NULL; + current_decoder = NULL; + + something_changed = FALSE; + can_write = FALSE; + gtk_widget_set_sensitive (btn_apply, FALSE); + + infowin_entry_set_image (image_artwork, DATA_DIR "/images/audio.png"); +} + +static void entry_changed (GtkEditable * editable, void * unused) +{ + if (! something_changed && can_write) + { + something_changed = TRUE; + gtk_widget_set_sensitive (btn_apply, TRUE); + } +} + +static gboolean ministatus_timeout_proc (void * data) +{ + GtkLabel * status = data; + + gtk_label_set_text (status, "<span size=\"small\"></span>"); + gtk_label_set_use_markup (status, TRUE); + + return FALSE; +} + +static void ministatus_display_message (const gchar * text) +{ + gchar * tmp = g_strdup_printf ("<span size=\"small\">%s</span>", text); + + gtk_label_set_text ((GtkLabel *) label_mini_status, tmp); + gtk_label_set_use_markup ((GtkLabel *) label_mini_status, TRUE); + g_free (tmp); + + g_timeout_add (STATUS_TIMEOUT, (GSourceFunc) ministatus_timeout_proc, + label_mini_status); +} + +static void infowin_update_tuple (void * unused) +{ + Tuple * tuple = tuple_new_from_filename (current_file); + + set_field_str_from_entry (tuple, FIELD_TITLE, entry_title); + set_field_str_from_entry (tuple, FIELD_ARTIST, entry_artist); + set_field_str_from_entry (tuple, FIELD_ALBUM, entry_album); + set_field_str_from_entry (tuple, FIELD_COMMENT, entry_comment); + set_field_str_from_entry (tuple, FIELD_GENRE, gtk_bin_get_child ((GtkBin *) + entry_genre)); + set_field_int_from_entry (tuple, FIELD_YEAR, entry_year); + set_field_int_from_entry (tuple, FIELD_TRACK_NUMBER, entry_track); + + if (aud_file_write_tuple (current_file, current_decoder, tuple)) + { + ministatus_display_message (_("Metadata updated successfully")); + something_changed = FALSE; + gtk_widget_set_sensitive (btn_apply, FALSE); + } + else + ministatus_display_message (_("Metadata updating failed")); + + mowgli_object_unref (tuple); +} + +/** + * Looks up an icon from a NULL-terminated list of icon names. + * + * size: the requested size + * name: the default name + * ... : a NULL-terminated list of alternates + */ +static GdkPixbuf * themed_icon_lookup (gint size, const gchar * name, ...) +{ + GtkIconTheme * icon_theme; + GdkPixbuf * pixbuf; + const gchar * n; + va_list par; + + icon_theme = gtk_icon_theme_get_default (); + pixbuf = gtk_icon_theme_load_icon (icon_theme, name, size, 0, NULL); + + if (pixbuf != NULL) + return pixbuf; + + /* fallback */ + va_start (par, name); + + while ((n = va_arg (par, const gchar *)) != NULL) + { + pixbuf = gtk_icon_theme_load_icon (icon_theme, n, size, 0, NULL); + + if (pixbuf) + { + va_end (par); + return pixbuf; + } + } + + va_end (par); + return NULL; +} + +/** + * Intelligently looks up an icon for a mimetype. Supports + * HIDEOUSLY BROKEN gnome icon naming scheme too. + * + * size : the requested size + * mime_type: the mime type. + */ +static GdkPixbuf * mime_icon_lookup (gint size, const gchar * mime_type) +{ + gchar * mime_as_is; /* audio-x-mp3 */ + gchar * mime_gnome; /* gnome-mime-audio-x-mp3 */ + gchar * mime_generic; /* audio-x-generic */ + gchar * mime_gnome_generic; /* gnome-mime-audio */ + GdkPixbuf * icon = NULL; + gchar * * s = g_strsplit (mime_type, "/", 2); + + if (s[1] != NULL) + { + mime_as_is = g_strdup_printf ("%s-%s", s[0], s[1]); + mime_gnome = g_strdup_printf ("gnome-mime-%s-%s", s[0], s[1]); + mime_generic = g_strdup_printf ("%s-x-generic", s[0]); + mime_gnome_generic = g_strdup_printf ("gnome-mime-%s", s[0]); + + icon = themed_icon_lookup (size, mime_as_is, mime_gnome, mime_generic, + mime_gnome_generic, s[0], NULL); /* s[0] is category */ + + g_free (mime_gnome_generic); + g_free (mime_generic); + g_free (mime_gnome); + g_free (mime_as_is); + } + + g_strfreev (s); + return icon; +} + +void create_infowin (void) +{ + GtkWidget * hbox; + GtkWidget * hbox_status_and_bbox; + GtkWidget * vbox0; + GtkWidget * vbox1; + GtkWidget * vbox2; + GtkWidget * vbox3; + GtkWidget * label_title; + GtkWidget * label_artist; + GtkWidget * label_album; + GtkWidget * label_comment; + GtkWidget * label_genre; + GtkWidget * label_year; + GtkWidget * label_track; + GtkWidget * label_location; + GtkWidget * label_general; + GtkWidget * label_format; + GtkWidget * label_quality_label; + GtkWidget * label_bitrate_label; + GtkWidget * codec_hbox; + GtkWidget * codec_table; + GtkWidget * table1; + GtkWidget * bbox_close; + GtkWidget * btn_close; + GtkWidget * alignment; + GtkWidget * separator; + GtkWidget * scrolledwindow; + GtkTreeViewColumn * column; + GtkCellRenderer * renderer; + gint i; + + infowin = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width ((GtkContainer *) infowin, 6); + gtk_window_set_title ((GtkWindow *) infowin, _("Track Information")); + gtk_window_set_type_hint ((GtkWindow *) infowin, + GDK_WINDOW_TYPE_HINT_DIALOG); + + vbox0 = gtk_vbox_new (FALSE, 0); + gtk_container_add ((GtkContainer *) infowin, vbox0); + + hbox = gtk_hbox_new (FALSE, 6); + gtk_box_pack_start ((GtkBox *) vbox0, hbox, TRUE, TRUE, 0); + + image_artwork = gtk_image_new (); + gtk_box_pack_start ((GtkBox *) hbox, image_artwork, FALSE, FALSE, 0); + gtk_misc_set_alignment ((GtkMisc *) image_artwork, 0.5, 0); + gtk_image_set_from_file ((GtkImage *) image_artwork, DATA_DIR + "/images/audio.png"); + separator = gtk_vseparator_new (); + gtk_box_pack_start ((GtkBox *) hbox, separator, FALSE, FALSE, 0); + + vbox1 = gtk_vbox_new (FALSE, 0); + gtk_box_pack_start ((GtkBox *) hbox, vbox1, TRUE, TRUE, 0); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_box_pack_start ((GtkBox *) vbox1, alignment, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 0); + gtk_container_add ((GtkContainer *) alignment, vbox2); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_box_pack_start ((GtkBox *) vbox1, alignment, TRUE, TRUE, 0); + + vbox3 = gtk_vbox_new(FALSE, 0); + gtk_container_add ((GtkContainer *) alignment, vbox3); + + label_general = gtk_label_new (_("<span size=\"small\">General</span>")); + gtk_box_pack_start ((GtkBox *) vbox2, label_general, FALSE, FALSE, 0); + gtk_label_set_use_markup ((GtkLabel *) label_general, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_general, 0, 0.5); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_alignment_set_padding ((GtkAlignment *) alignment, 6, 6, 0, 0); + gtk_box_pack_start ((GtkBox *) vbox2, alignment, FALSE, FALSE, 0); + + codec_hbox = gtk_hbox_new (FALSE, 6); + gtk_container_add ((GtkContainer *) alignment, codec_hbox); + + image_fileicon = gtk_image_new_from_stock (GTK_STOCK_MISSING_IMAGE, + GTK_ICON_SIZE_DIALOG); + gtk_box_pack_start ((GtkBox *) codec_hbox, image_fileicon, FALSE, FALSE, 0); + + codec_table = gtk_table_new(3, 2, FALSE); + gtk_table_set_row_spacings ((GtkTable *) codec_table, 6); + gtk_table_set_col_spacings ((GtkTable *) codec_table, 12); + gtk_box_pack_start ((GtkBox *) codec_hbox, codec_table, FALSE, FALSE, 0); + + label_format = gtk_label_new (_("<span size=\"small\">Format:</span>")); + gtk_label_set_use_markup ((GtkLabel *) label_format, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_format, 0, 0.5); + label_quality_label = gtk_label_new + (_("<span size=\"small\">Quality:</span>")); + gtk_label_set_use_markup ((GtkLabel *) label_quality_label, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_quality_label, 0, 0.5); + label_bitrate_label = gtk_label_new (_("<span size=\"small\">Bitrate:</span>")); + gtk_label_set_use_markup ((GtkLabel *) label_bitrate_label, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_bitrate_label, 0, 0.5); + + label_format_name = gtk_label_new (_("<span size=\"small\">n/a</span>")); + gtk_label_set_use_markup ((GtkLabel *) label_format_name, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_format_name, 0, 0.5); + label_quality = gtk_label_new (_("<span size=\"small\">n/a</span>")); + gtk_label_set_use_markup ((GtkLabel *) label_quality, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_quality, 0, 0.5); + label_bitrate = gtk_label_new (_("<span size=\"small\">n/a</span>")); + gtk_label_set_use_markup ((GtkLabel *) label_bitrate, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_bitrate, 0, 0.5); + + gtk_table_attach ((GtkTable *) codec_table, label_format, 0, 1, 0, 1, + GTK_EXPAND | GTK_FILL, 0, 0, 0); + gtk_table_attach ((GtkTable *) codec_table, label_format_name, 1, 2, 0, 1, + GTK_EXPAND | GTK_FILL, 0, 0, 0); + gtk_table_attach ((GtkTable *) codec_table, label_quality_label, 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, 0, 0, 0); + gtk_table_attach ((GtkTable *) codec_table, label_quality, 1, 2, 1, 2, + GTK_EXPAND | GTK_FILL, 0, 0, 0); + gtk_table_attach ((GtkTable *) codec_table, label_bitrate_label, 0, 1, 2, 3, + GTK_EXPAND | GTK_FILL, 0, 0, 0); + gtk_table_attach ((GtkTable *) codec_table, label_bitrate, 1, 2, 2, 3, + GTK_EXPAND | GTK_FILL, 0, 0, 0); + + label_title = gtk_label_new (_("<span size=\"small\">Title</span>")); + gtk_box_pack_start ((GtkBox *) vbox2, label_title, FALSE, FALSE, 0); + gtk_label_set_use_markup ((GtkLabel *) label_title, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_title, 0, 0); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_box_pack_start ((GtkBox *) vbox2, alignment, FALSE, FALSE, 0); + gtk_alignment_set_padding ((GtkAlignment *) alignment, 0, 6, 0, 0); + entry_title = gtk_entry_new (); + gtk_container_add ((GtkContainer *) alignment, entry_title); + g_signal_connect (entry_title, "changed", (GCallback) entry_changed, NULL); + + label_artist = gtk_label_new (_("<span size=\"small\">Artist</span>")); + gtk_box_pack_start ((GtkBox *) vbox2, label_artist, FALSE, FALSE, 0); + gtk_label_set_use_markup ((GtkLabel *) label_artist, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_artist, 0, 0.5); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_box_pack_start ((GtkBox *) vbox2, alignment, FALSE, FALSE, 0); + gtk_alignment_set_padding ((GtkAlignment *) alignment, 0, 6, 0, 0); + entry_artist = gtk_entry_new (); + gtk_container_add ((GtkContainer *) alignment, entry_artist); + g_signal_connect (entry_artist, "changed", (GCallback) entry_changed, NULL); + + label_album = gtk_label_new (_("<span size=\"small\">Album</span>")); + gtk_box_pack_start ((GtkBox *) vbox2, label_album, FALSE, FALSE, 0); + gtk_label_set_use_markup ((GtkLabel *) label_album, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_album, 0, 0.5); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_box_pack_start ((GtkBox *) vbox2, alignment, FALSE, FALSE, 0); + gtk_alignment_set_padding ((GtkAlignment *) alignment, 0, 6, 0, 0); + entry_album = gtk_entry_new (); + gtk_container_add ((GtkContainer *) alignment, entry_album); + g_signal_connect (entry_album, "changed", (GCallback) entry_changed, NULL); + + label_comment = gtk_label_new (_("<span size=\"small\">Comment</span>")); + gtk_box_pack_start ((GtkBox *) vbox2, label_comment, FALSE, FALSE, 0); + gtk_label_set_use_markup ((GtkLabel *) label_comment, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_comment, 0, 0.5); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_box_pack_start ((GtkBox *) vbox2, alignment, FALSE, FALSE, 0); + gtk_alignment_set_padding ((GtkAlignment *) alignment, 0, 6, 0, 0); + entry_comment = gtk_entry_new (); + gtk_container_add ((GtkContainer *) alignment, entry_comment); + g_signal_connect (entry_comment, "changed", (GCallback) entry_changed, NULL); + + label_genre = gtk_label_new (_("<span size=\"small\">Genre</span>")); + gtk_box_pack_start ((GtkBox *) vbox2, label_genre, FALSE, FALSE, 0); + gtk_label_set_use_markup ((GtkLabel *) label_genre, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_genre, 0, 0.5); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_box_pack_start ((GtkBox *) vbox2, alignment, FALSE, FALSE, 0); + gtk_alignment_set_padding ((GtkAlignment *) alignment, 0, 6, 0, 0); + entry_genre = gtk_combo_box_entry_new_text (); + + if (genre_list == NULL) + { + GList * iter; + + for (i = 0; i < G_N_ELEMENTS (genre_table); i ++) + genre_list = g_list_prepend (genre_list, _(genre_table[i])); + + genre_list = g_list_sort (genre_list, (GCompareFunc) g_utf8_collate); + + for (iter = genre_list; iter != NULL; iter = iter->next) + gtk_combo_box_append_text ((GtkComboBox *) entry_genre, iter->data); + } + + gtk_container_add ((GtkContainer *) alignment, entry_genre); + g_signal_connect (entry_genre, "changed", (GCallback) entry_changed, NULL); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_box_pack_start ((GtkBox *) vbox2, alignment, FALSE, FALSE, 0); + gtk_alignment_set_padding ((GtkAlignment *) alignment, 0, 6, 0, 0); + table1 = gtk_table_new (2, 2, FALSE); + gtk_container_add ((GtkContainer *) alignment, table1); + gtk_table_set_col_spacings ((GtkTable *) table1, 6); + + label_year = gtk_label_new (_("<span size=\"small\">Year</span>")); + gtk_table_attach ((GtkTable *) table1, label_year, 0, 1, 0, 1, GTK_FILL, 0, + 0, 0); + gtk_label_set_use_markup ((GtkLabel *) label_year, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_year, 0, 0.5); + + entry_year = gtk_entry_new (); + gtk_table_attach ((GtkTable *) table1, entry_year, 0, 1, 1, 2, GTK_EXPAND | + GTK_FILL, 0, 0, 0); + g_signal_connect (entry_year, "changed", (GCallback) entry_changed, NULL); + + label_track = gtk_label_new (_("<span size=\"small\">Track Number</span>")); + gtk_table_attach ((GtkTable *) table1, label_track, 1, 2, 0, 1, GTK_FILL, 0, + 0, 0); + gtk_label_set_use_markup ((GtkLabel *) label_track, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_track, 0, 0.5); + + entry_track = gtk_entry_new (); + gtk_table_attach ((GtkTable *) table1, entry_track, 1, 2, 1, 2, GTK_EXPAND | + GTK_FILL, 0, 0, 0); + g_signal_connect (entry_track, "changed", (GCallback) entry_changed, NULL); + + label_location = gtk_label_new (_("<span size=\"small\">Location</span>")); + gtk_box_pack_start ((GtkBox *) vbox2, label_location, FALSE, FALSE, 0); + gtk_label_set_use_markup ((GtkLabel *) label_location, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_location, 0, 0.5); + + alignment = gtk_alignment_new (0, 0, 0, 0); + gtk_alignment_set_padding ((GtkAlignment *) alignment, 3, 6, 25, 0); + gtk_box_pack_start ((GtkBox *) vbox2, alignment, FALSE, FALSE, 0); + + location_text = gtk_label_new (""); + gtk_widget_set_size_request (location_text, 375, -1); + gtk_label_set_line_wrap ((GtkLabel *) location_text, TRUE); +#if GTK_CHECK_VERSION (2, 10, 0) + gtk_label_set_line_wrap_mode ((GtkLabel *) location_text, + PANGO_WRAP_WORD_CHAR); +#endif + gtk_label_set_selectable ((GtkLabel *) location_text, TRUE); + gtk_container_add ((GtkContainer *) alignment, location_text); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + hbox = gtk_hbox_new (FALSE, 0); + gtk_container_add ((GtkContainer *) alignment, hbox); + gtk_box_pack_start ((GtkBox *) vbox3, alignment, TRUE, TRUE, 0); + + alignment = gtk_alignment_new (0.5, 0.5, 1, 1); + gtk_alignment_set_padding ((GtkAlignment *) (alignment), 0, 6, 0, 0); + arrow_rawdata = gtk_expander_new + (_("<span size=\"small\">Raw Metadata</span>")); + gtk_expander_set_use_markup ((GtkExpander *) arrow_rawdata, TRUE); + gtk_container_add ((GtkContainer *) alignment, arrow_rawdata); + gtk_box_pack_start ((GtkBox *) hbox, alignment, TRUE, TRUE, 0); + + scrolledwindow = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy ((GtkScrolledWindow *) scrolledwindow, + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type ((GtkScrolledWindow *) scrolledwindow, + GTK_SHADOW_IN); + gtk_container_add ((GtkContainer *) arrow_rawdata, scrolledwindow); + + treeview_rawdata = gtk_tree_view_new (); + gtk_container_add ((GtkContainer *) scrolledwindow, treeview_rawdata); + gtk_tree_view_set_rules_hint ((GtkTreeView *) treeview_rawdata, TRUE); + gtk_tree_view_set_reorderable ((GtkTreeView *) treeview_rawdata, TRUE); + gtk_widget_set_size_request (treeview_rawdata, -1, 130); + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title (column, _("Key")); + gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_spacing (column, 4); + gtk_tree_view_column_set_resizable (column, FALSE); + gtk_tree_view_column_set_fixed_width (column, 50); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_set_attributes (column, renderer, "text", RAWDATA_KEY, + NULL); + gtk_tree_view_append_column ((GtkTreeView *) treeview_rawdata, column); + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title (column, _("Value")); + gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + gtk_tree_view_column_set_spacing (column, 4); + gtk_tree_view_column_set_resizable (column, FALSE); + gtk_tree_view_column_set_fixed_width (column, 50); + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, renderer, FALSE); + gtk_tree_view_column_set_attributes (column, renderer, "text", + RAWDATA_VALUE, NULL); + gtk_tree_view_append_column ((GtkTreeView *) treeview_rawdata, column); + + hbox_status_and_bbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start ((GtkBox *) vbox0, hbox_status_and_bbox, FALSE, FALSE, 0); + + label_mini_status = gtk_label_new ("<span size=\"small\"></span>"); + gtk_label_set_use_markup ((GtkLabel *) label_mini_status, TRUE); + gtk_misc_set_alignment ((GtkMisc *) label_mini_status, 0, 0.5); + gtk_box_pack_start ((GtkBox *) hbox_status_and_bbox, label_mini_status, + TRUE, TRUE, 0); + + bbox_close = gtk_hbutton_box_new (); + gtk_box_set_spacing ((GtkBox *) bbox_close, 6); + gtk_box_pack_start ((GtkBox *) hbox_status_and_bbox, bbox_close, FALSE, + FALSE, 0); + gtk_button_box_set_layout ((GtkButtonBox *) bbox_close, GTK_BUTTONBOX_END); + + btn_apply = gtk_button_new_from_stock (GTK_STOCK_SAVE); + gtk_container_add ((GtkContainer *) bbox_close, btn_apply); + g_signal_connect (btn_apply, "clicked", (GCallback) infowin_update_tuple, + NULL); + gtk_widget_set_sensitive (btn_apply, FALSE); + + btn_close = gtk_button_new_from_stock (GTK_STOCK_CLOSE); + gtk_container_add ((GtkContainer *) bbox_close, btn_close); + GTK_WIDGET_SET_FLAGS (btn_close, GTK_CAN_DEFAULT); + g_signal_connect_swapped (btn_close, "clicked", (GCallback) gtk_widget_hide, + infowin); + + audgui_hide_on_delete (infowin); + audgui_hide_on_escape (infowin); + + gtk_widget_show_all (vbox0); +} + +/* Converts filenames (in place) for easy reading, thus: + * + * file:///home/me/Music/My song.ogg -> Music + * My song.ogg + * + * file:///media/disk/My song.ogg -> / + * media + * disk + * My song.ogg + */ +static gchar * easy_read_filename (gchar * file) +{ + const gchar * home; + gint len; + + if (strncmp (file, "file:///", 8)) + return file; + + home = getenv ("HOME"); + len = (home == NULL) ? 0 : strlen (home); + len = (len > 0 && home[len - 1] == '/') ? len - 1 : len; + + if (len > 0 && ! strncmp (file + 7, home, len) && file[len + 7] == '/') + { + string_replace_char (file + len + 8, '/', '\n'); + return file + len + 8; + } + + string_replace_char (file + 7, '/', '\n'); + return file + 6; +} + +static gboolean set_image_from_album_art (const gchar * filename, InputPlugin * + decoder) +{ + GdkPixbuf * pixbuf = NULL; + void * data; + gint size; + + if (aud_file_read_image (filename, decoder, & data, & size)) + { + pixbuf = audgui_pixbuf_from_data (data, size); + g_free (data); + } + + if (pixbuf == NULL) + return FALSE; + + audgui_pixbuf_scale_within (& pixbuf, aud_cfg->filepopup_pixelsize); + gtk_image_set_from_pixbuf ((GtkImage *) image_artwork, pixbuf); + g_object_unref (pixbuf); + return TRUE; +} + +static void infowin_show (const gchar * filename, Tuple * tuple, InputPlugin * + decoder, gboolean updating_enabled) +{ + const gchar * string; + gchar * tmp; + GdkPixbuf * icon; + GtkTreeIter iter; + GtkListStore * store; + mowgli_dictionary_iteration_state_t state; + TupleValue * tvalue; + gint i; + + if (infowin == NULL) + create_infowin (); + else + clear_infowin (); + + current_file = g_strdup (filename); + current_decoder = decoder; + can_write = updating_enabled; + + set_entry_str_from_field (entry_title, tuple, FIELD_TITLE, updating_enabled); + set_entry_str_from_field (entry_artist, tuple, FIELD_ARTIST, + updating_enabled); + set_entry_str_from_field (entry_album, tuple, FIELD_ALBUM, updating_enabled); + set_entry_str_from_field (entry_comment, tuple, FIELD_COMMENT, + updating_enabled); + set_entry_str_from_field (gtk_bin_get_child ((GtkBin *) entry_genre), tuple, + FIELD_GENRE, updating_enabled); + + tmp = g_strdup (filename); + string_decode_percent (tmp); + gtk_label_set_text ((GtkLabel *) location_text, easy_read_filename (tmp)); + g_free (tmp); + + set_entry_int_from_field (entry_year, tuple, FIELD_YEAR, updating_enabled); + set_entry_int_from_field (entry_track, tuple, FIELD_TRACK_NUMBER, + updating_enabled); + + infowin_label_set_text (label_format_name, tuple_get_string (tuple, + FIELD_CODEC, NULL)); + infowin_label_set_text (label_quality, tuple_get_string (tuple, + FIELD_QUALITY, NULL)); + + if (tuple_get_value_type (tuple, FIELD_BITRATE, NULL) == TUPLE_INT) + { + tmp = g_strdup_printf (_("%d kb/s"), tuple_get_int (tuple, + FIELD_BITRATE, NULL)); + infowin_label_set_text (label_bitrate, tmp); + g_free (tmp); + } + else + infowin_label_set_text (label_bitrate, NULL); + + string = tuple_get_string (tuple, FIELD_MIMETYPE, NULL); + icon = mime_icon_lookup (48, string != NULL ? string : "audio/x-generic"); + + if (icon != NULL) + { + gtk_image_set_from_pixbuf ((GtkImage *) image_fileicon, icon); + g_object_unref (icon); + } + + if (! set_image_from_album_art (filename, decoder)) + { + tmp = aud_get_associated_image_file (filename); + + if (tmp != NULL) + { + infowin_entry_set_image (image_artwork, tmp); + g_free (tmp); + } + } + + store = gtk_list_store_new (RAWDATA_N_COLS, G_TYPE_STRING, G_TYPE_STRING); + + for (i = 0; i < FIELD_LAST; i ++) + { + gchar * value; + + if (tuple->values[i] == NULL) + continue; + + if (tuple->values[i]->type == TUPLE_INT) + value = g_strdup_printf ("%d", tuple->values[i]->value.integer); + else if (tuple->values[i]->value.string != NULL) + value = g_strdup (tuple->values[i]->value.string); + else + continue; + + gtk_list_store_append (store, & iter); + gtk_list_store_set (store, & iter, RAWDATA_KEY, tuple_fields[i].name, + RAWDATA_VALUE, value, -1); + g_free (value); + } + + /* non-standard values are stored in a dictionary. */ + MOWGLI_DICTIONARY_FOREACH (tvalue, & state, tuple->dict) + { + gchar * value; + + if (tvalue->type == TUPLE_INT) + value = g_strdup_printf ("%d", tvalue->value.integer); + else if (tvalue->value.string != NULL) + value = g_strdup (tvalue->value.string); + else + continue; + + gtk_list_store_append (store, & iter); + gtk_list_store_set (store, & iter, RAWDATA_KEY, state.cur->key, + RAWDATA_VALUE, value, -1); + g_free (value); + } + + gtk_tree_view_set_model ((GtkTreeView *) treeview_rawdata, (GtkTreeModel *) + store); + g_object_unref (store); + + gtk_window_present ((GtkWindow *) infowin); +} + +void audgui_infowin_show (gint playlist, gint entry) +{ + const gchar * filename = aud_playlist_entry_get_filename (playlist, entry); + InputPlugin * decoder = aud_playlist_entry_get_decoder (playlist, entry); + Tuple * tuple; + + g_return_if_fail (filename != NULL); + + if (decoder == NULL) + { + decoder = aud_file_find_decoder (filename, FALSE); + + if (decoder == NULL) + return; + } + + if (aud_custom_infowin (filename, decoder)) + return; + + tuple = aud_file_read_tuple (filename, decoder); + + if (tuple == NULL) + { + gchar * message = g_strdup_printf (_("No info available for %s.\n"), + filename); + + aud_hook_call ("interface show error", message); + g_free (message); + return; + } + + infowin_show (filename, tuple, decoder, aud_file_can_write_tuple (filename, + decoder)); + + aud_playlist_entry_set_tuple (playlist, entry, tuple); + /* We do not unref the tuple, as the playlist takes ownership. */ +} + +void audgui_infowin_show_current (void) +{ + gint playlist = aud_playlist_get_playing (); + gint position; + + if (playlist == -1) + playlist = aud_playlist_get_active (); + + position = aud_playlist_get_position (playlist); + + if (position == -1) + return; + + audgui_infowin_show (playlist, position); +} diff --git a/src/libaudgui/init.c b/src/libaudgui/init.c new file mode 100644 index 0000000..ae1d1c0 --- /dev/null +++ b/src/libaudgui/init.c @@ -0,0 +1,29 @@ +/* + * libaudgui/init.c + * Copyright 2010 John Lindgren + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 or version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#include <audacious/plugin.h> + +struct _AudaciousFuncTableV1 * _audvt; + +void audgui_init (struct _AudaciousFuncTableV1 * vtable) +{ + _audvt = vtable; +} diff --git a/src/libaudgui/init.h b/src/libaudgui/init.h new file mode 100644 index 0000000..cbe0c79 --- /dev/null +++ b/src/libaudgui/init.h @@ -0,0 +1,24 @@ +/* + * libaudgui/init.h + * Copyright 2010 John Lindgren + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 or version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#include <audacious/plugin.h> + +void audgui_init (struct _AudaciousFuncTableV1 * vtable); diff --git a/src/libaudgui/libaudgui-gtk.h b/src/libaudgui/libaudgui-gtk.h index ff07068..e6ac739 100644 --- a/src/libaudgui/libaudgui-gtk.h +++ b/src/libaudgui/libaudgui-gtk.h @@ -22,6 +22,34 @@ #ifndef LIBAUDGUI_GTK_H #define LIBAUDGUI_GTK_H +#include <gtk/gtk.h> + GtkWidget * audgui_create_effects_menu (void); +void audgui_playlist_manager_update(void); +void audgui_playlist_manager_ui_show(GtkWidget *mainwin); +void audgui_playlist_manager_destroy(void); + +/* library-store.c */ +enum +{ + AUDGUI_LIBRARY_STORE_TITLE, /* G_TYPE_STRING */ + AUDGUI_LIBRARY_STORE_FONT_WEIGHT, /* PANGO_TYPE_WEIGHT */ + AUDGUI_LIBRARY_STORE_ENTRY_COUNT, /* G_TYPE_INT */ + AUDGUI_LIBRARY_STORE_COLUMNS +}; + +GtkTreeModel * audgui_get_library_store (void); + +/* util.c */ +void audgui_hide_on_delete (GtkWidget * widget); +void audgui_hide_on_escape (GtkWidget * widget); +void audgui_destroy_on_escape (GtkWidget * widget); +void audgui_simple_message (GtkWidget * * widget, GtkMessageType type, + const gchar * title, const gchar * text); +void audgui_connect_check_box (GtkWidget * box, gboolean * setting); + +GdkPixbuf * audgui_pixbuf_from_data (void * data, gint size); +void audgui_pixbuf_scale_within (GdkPixbuf * * pixbuf, gint size); + #endif diff --git a/src/libaudgui/libaudgui.h b/src/libaudgui/libaudgui.h index 924bcfd..828fafd 100644 --- a/src/libaudgui/libaudgui.h +++ b/src/libaudgui/libaudgui.h @@ -1,5 +1,5 @@ /* Audacious - Cross-platform multimedia player - * Copyright (C) 2005-2009 Audacious development team. + * Copyright (C) 2005-2010 Audacious development team. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,4 +43,16 @@ void audgui_hide_filebrowser(void); void audgui_show_about_window(void); void audgui_hide_about_window(void); +/* confirm.c */ +void audgui_confirm_playlist_delete (gint playlist); + +/* infopopup.c */ +void audgui_infopopup_show (gint playlist, gint entry); +void audgui_infopopup_show_current (void); +void audgui_infopopup_hide (void); + +/* infowin.c */ +void audgui_infowin_show (gint playlist, gint entry); +void audgui_infowin_show_current (void); + #endif /* LIBAUDGUI_H */ diff --git a/src/libaudgui/library-store.c b/src/libaudgui/library-store.c new file mode 100644 index 0000000..b2054bf --- /dev/null +++ b/src/libaudgui/library-store.c @@ -0,0 +1,366 @@ +/* + * libaudgui/library-store.c + * Copyright 2010 John Lindgren + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 or version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#include <audacious/plugin.h> + +#include "libaudgui-gtk.h" + +typedef GObjectClass LibraryStoreClass; + +typedef struct +{ + GObject parent; + gint rows, active; +} +LibraryStore; + +static void library_store_init (LibraryStore * store) +{ + store->rows = aud_playlist_count (); + store->active = aud_playlist_get_active (); +} + +static GtkTreeModelFlags library_store_get_flags (GtkTreeModel * model) +{ + return GTK_TREE_MODEL_LIST_ONLY; +} + +static gint library_store_get_n_columns (GtkTreeModel * model) +{ + return AUDGUI_LIBRARY_STORE_COLUMNS; +} + +static GType library_store_get_column_type (GtkTreeModel * model, gint column) +{ + switch (column) + { + case AUDGUI_LIBRARY_STORE_TITLE: + return G_TYPE_STRING; + case AUDGUI_LIBRARY_STORE_FONT_WEIGHT: + return PANGO_TYPE_WEIGHT; + case AUDGUI_LIBRARY_STORE_ENTRY_COUNT: + return G_TYPE_INT; + default: + return G_TYPE_INVALID; + } +} + +static gboolean library_store_get_iter (GtkTreeModel * model, GtkTreeIter * + iter, GtkTreePath * path) +{ + LibraryStore * store = (LibraryStore *) model; + gint playlist = gtk_tree_path_get_indices (path)[0]; + + if (playlist < 0 || playlist >= store->rows) + return FALSE; + + iter->user_data = GINT_TO_POINTER (playlist); + return TRUE; +} + +static GtkTreePath * library_store_get_path (GtkTreeModel * model, GtkTreeIter * + iter) +{ + return gtk_tree_path_new_from_indices (GPOINTER_TO_INT (iter->user_data), -1); +} + +static void library_store_get_value (GtkTreeModel * model, GtkTreeIter * iter, + gint column, GValue * value) +{ + LibraryStore * store = (LibraryStore *) model; + gint playlist = GPOINTER_TO_INT (iter->user_data); + + switch (column) + { + case AUDGUI_LIBRARY_STORE_TITLE: + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, aud_playlist_get_title (playlist)); + break; + case AUDGUI_LIBRARY_STORE_FONT_WEIGHT: + g_value_init (value, PANGO_TYPE_WEIGHT); + g_value_set_enum (value, (playlist == store->active) ? PANGO_WEIGHT_BOLD + : PANGO_WEIGHT_NORMAL); + break; + case AUDGUI_LIBRARY_STORE_ENTRY_COUNT: + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, aud_playlist_entry_count (playlist)); + break; + } +} + +static gboolean library_store_iter_next (GtkTreeModel * model, GtkTreeIter * + iter) +{ + if (GPOINTER_TO_INT (iter->user_data) + 1 < aud_playlist_count ()) + { + iter->user_data = GINT_TO_POINTER (GPOINTER_TO_INT (iter->user_data) + 1); + return TRUE; + } + + return FALSE; +} + +static gboolean library_store_iter_children (GtkTreeModel * model, GtkTreeIter * + iter, GtkTreeIter * parent) +{ + if (parent == NULL) /* top level */ + { + /* there is always at least one playlist */ + iter->user_data = GINT_TO_POINTER (0); + return TRUE; + } + + return FALSE; +} + +static gboolean library_store_iter_has_child (GtkTreeModel * model, + GtkTreeIter * iter) +{ + return FALSE; +} + +static gint library_store_iter_n_children (GtkTreeModel * model, GtkTreeIter * + iter) +{ + LibraryStore * store = (LibraryStore *) model; + + if (iter == NULL) /* top level */ + return store->rows; + + return 0; +} + +static gboolean library_store_iter_nth_child (GtkTreeModel * model, + GtkTreeIter * iter, GtkTreeIter * parent, gint n) +{ + LibraryStore * store = (LibraryStore *) model; + + if (parent != NULL) /* not top level */ + return FALSE; + + if (n < 0 || n >= store->rows) + return FALSE; + + iter->user_data = GINT_TO_POINTER (n); + return TRUE; +} + +static gboolean library_store_iter_parent (GtkTreeModel * model, GtkTreeIter * + iter, GtkTreeIter * child) +{ + return FALSE; +} + +static void interface_init (GtkTreeModelIface * interface) +{ + interface->get_flags = library_store_get_flags; + interface->get_n_columns = library_store_get_n_columns; + interface->get_column_type = library_store_get_column_type; + interface->get_iter = library_store_get_iter; + interface->get_path = library_store_get_path; + interface->get_value = library_store_get_value; + interface->iter_next = library_store_iter_next; + interface->iter_children = library_store_iter_children; + interface->iter_has_child = library_store_iter_has_child; + interface->iter_n_children = library_store_iter_n_children; + interface->iter_nth_child = library_store_iter_nth_child; + interface->iter_parent = library_store_iter_parent; +} + +static const GInterfaceInfo interface_info = +{ + .interface_init = (GInterfaceInitFunc) interface_init, + .interface_finalize = NULL, + .interface_data = NULL, +}; + +static gboolean library_store_drag_data_get (GtkTreeDragSource * source, + GtkTreePath * path, GtkSelectionData * data) +{ + return gtk_tree_set_row_drag_data (data, (GtkTreeModel *) source, path); +} + +static gboolean library_store_drag_data_delete (GtkTreeDragSource * source, + GtkTreePath * path) +{ + return TRUE; +} + +static void source_init (GtkTreeDragSourceIface * interface) +{ + interface->drag_data_get = library_store_drag_data_get; + interface->drag_data_delete = library_store_drag_data_delete; +} + +static const GInterfaceInfo source_info = +{ + .interface_init = (GInterfaceInitFunc) source_init, + .interface_finalize = NULL, + .interface_data = NULL, +}; + +static gboolean library_store_drag_data_received (GtkTreeDragDest * dest, + GtkTreePath * dest_path, GtkSelectionData * data) +{ + LibraryStore * store = (LibraryStore *) dest; + GtkTreeModel * model; + GtkTreePath * source_path, * top; + gint from, to, count; + gint order[store->rows]; + + if (! gtk_tree_get_row_drag_data (data, & model, & source_path)) + return FALSE; + + from = gtk_tree_path_get_indices (source_path)[0]; + to = gtk_tree_path_get_indices (dest_path)[0]; + + /* GTK gives us the number of the row before which we are to put the row. + * We want the number of the row where the row will end up. */ + if (to > from) + to --; + + if (from < 0 || from >= store->rows || to < 0 || to >= store->rows) + return FALSE; + + aud_playlist_reorder (from, to, 1); + + for (count = 0; count < from; count ++) + order[count] = count; + + if (from < to) + { + for (count = from; count < to; count ++) + order[count] = count + 1; + } + else + { + for (count = to; count < from; count ++) + order[count + 1] = count; + } + + order[to] = from; + + top = gtk_tree_path_new (); + gtk_tree_model_rows_reordered (model, top, NULL, order); + gtk_tree_path_free (top); + + return TRUE; +} + +gboolean library_store_row_drop_possible (GtkTreeDragDest * dest, + GtkTreePath * path, GtkSelectionData * selection_data) +{ + LibraryStore * store = (LibraryStore *) dest; + gint before = gtk_tree_path_get_indices (path)[0]; + + return (before >= 0 && before <= store->rows); +} + +static void dest_init (GtkTreeDragDestIface * interface) +{ + interface->drag_data_received = library_store_drag_data_received; + interface->row_drop_possible = library_store_row_drop_possible; +} + +static const GInterfaceInfo dest_info = +{ + .interface_init = (GInterfaceInitFunc) dest_init, + .interface_finalize = NULL, + .interface_data = NULL, +}; + +static GType library_store_get_type (void) +{ + static GType type = 0; + + if (! type) + { + type = g_type_register_static_simple (G_TYPE_OBJECT, "LibraryStore", + sizeof (LibraryStoreClass), NULL, sizeof (LibraryStore), + (GInstanceInitFunc) library_store_init, 0); + g_type_add_interface_static (type, GTK_TYPE_TREE_MODEL, & interface_info); + g_type_add_interface_static (type, GTK_TYPE_TREE_DRAG_SOURCE, + & source_info); + g_type_add_interface_static (type, GTK_TYPE_TREE_DRAG_DEST, & dest_info); + } + + return type; +} + +static void library_store_update (GtkTreeModel * model) +{ + LibraryStore * store = (LibraryStore *) model; + gint old_rows = store->rows; + GtkTreePath * path; + GtkTreeIter iter; + gint row; + + store->rows = aud_playlist_count (); + store->active = aud_playlist_get_active (); + + if (store->rows < old_rows) + { + path = gtk_tree_path_new_from_indices (store->rows, -1); + + for (row = store->rows; row < old_rows; row ++) + gtk_tree_model_row_deleted (model, path); + + gtk_tree_path_free (path); + old_rows = store->rows; + } + + path = gtk_tree_path_new_first (); + + for (row = 0; row < old_rows; row ++) + { + iter.user_data = GINT_TO_POINTER (row); + gtk_tree_model_row_changed (model, path, & iter); + gtk_tree_path_next (path); + } + + for (; row < store->rows; row ++) + { + iter.user_data = GINT_TO_POINTER (row); + gtk_tree_model_row_inserted (model, path, & iter); + gtk_tree_path_next (path); + } + + gtk_tree_path_free (path); +} + +static void update_cb (void * data, void * user_data) +{ + if (GPOINTER_TO_INT (data) >= PLAYLIST_UPDATE_STRUCTURE) + library_store_update ((GtkTreeModel *) user_data); +} + +GtkTreeModel * audgui_get_library_store (void) +{ + static GtkTreeModel * store = NULL; + + if (store == NULL) + { + store = (GtkTreeModel *) g_object_new (library_store_get_type (), NULL); + aud_hook_associate ("playlist update", update_cb, store); + } + + return store; +} diff --git a/src/libaudgui/ui_jumptotrack.c b/src/libaudgui/ui_jumptotrack.c index def34a8..02afe99 100644 --- a/src/libaudgui/ui_jumptotrack.c +++ b/src/libaudgui/ui_jumptotrack.c @@ -329,6 +329,12 @@ static void watchdog (void * hook_data, void * user_data) NULL) return; + if (cache != NULL) + { + ui_jump_to_track_cache_free (cache); + cache = NULL; + } + tree = g_object_get_data (storage, "treeview"); /* If it's only a metadata update, save and restore the cursor position. */ diff --git a/src/libaudgui/ui_playlist_manager.c b/src/libaudgui/ui_playlist_manager.c new file mode 100644 index 0000000..2c24374 --- /dev/null +++ b/src/libaudgui/ui_playlist_manager.c @@ -0,0 +1,263 @@ +/* Audacious - Cross-platform multimedia player + * Copyright (C) 2005-2010 Audacious development team. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses>. + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include <audacious/i18n.h> +#include <audacious/plugin.h> + +#include "libaudgui.h" +#include "libaudgui-gtk.h" + +static gint iter_to_row (GtkTreeModel * model, GtkTreeIter * iter) +{ + GtkTreePath * path = gtk_tree_model_get_path (model, iter); + gint row = gtk_tree_path_get_indices (path)[0]; + + gtk_tree_path_free (path); + return row; +} + +static gint get_selected_row (GtkWidget * list) +{ + GtkTreeSelection * selection = gtk_tree_view_get_selection ((GtkTreeView *) + list); + GtkTreeModel * model; + GtkTreeIter iter; + + if (! gtk_tree_selection_get_selected (selection, & model, & iter)) + return -1; + + return iter_to_row (model, & iter); +} + +static void set_selected_row (GtkWidget * list, gint row) +{ + GtkTreeSelection * selection = gtk_tree_view_get_selection ((GtkTreeView *) + list); + GtkTreePath * path = gtk_tree_path_new_from_indices (row, -1); + + gtk_tree_selection_select_path (selection, path); + gtk_tree_path_free (path); +} + +static void save_position (GtkWidget * window) +{ + gtk_window_get_position ((GtkWindow *) window, + & aud_cfg->playlist_manager_x, & aud_cfg->playlist_manager_y); + gtk_window_get_size ((GtkWindow *) window, + & aud_cfg->playlist_manager_width, & aud_cfg->playlist_manager_height); +} + +static gboolean hide_cb (GtkWidget * window) +{ + save_position (window); + gtk_widget_hide (window); + return TRUE; +} + +static void activate_cb (GtkTreeView * list, GtkTreePath * path, + GtkTreeViewColumn * column, GtkWidget * window) +{ + aud_playlist_set_active (gtk_tree_path_get_indices (path)[0]); + + if (aud_cfg->playlist_manager_close_on_activate) + hide_cb (window); +} + +static void new_cb (GtkButton * button, void * unused) +{ + aud_playlist_insert (-1); +} + +static void delete_cb (GtkButton * button, GtkWidget * list) +{ + gint playlist = get_selected_row (list); + + if (playlist != -1) + audgui_confirm_playlist_delete (playlist); +} + +static void rename_cb (GtkButton * button, GtkWidget * lv) +{ + GtkTreeSelection *listsel = gtk_tree_view_get_selection( GTK_TREE_VIEW(lv) ); + GtkTreeModel *store; + GtkTreeIter iter; + + if ( gtk_tree_selection_get_selected( listsel , &store , &iter ) == TRUE ) + { + GtkTreePath *path = gtk_tree_model_get_path( GTK_TREE_MODEL(store) , &iter ); + GtkCellRenderer *rndrname = g_object_get_data( G_OBJECT(lv) , "rn" ); + /* set the name renderer to editable and start editing */ + g_object_set( G_OBJECT(rndrname) , "editable" , TRUE , NULL ); + gtk_tree_view_set_cursor_on_cell ((GtkTreeView *) lv, path, + gtk_tree_view_get_column ((GtkTreeView *) lv, + AUDGUI_LIBRARY_STORE_TITLE), rndrname, TRUE); + gtk_tree_path_free( path ); + } +} + +static void +playlist_manager_cb_lv_name_edited ( GtkCellRendererText *cell , gchar *path_string , + gchar *new_text , gpointer listview ) +{ + /* this is currently used to change playlist names */ + GtkTreeModel *store = gtk_tree_view_get_model( GTK_TREE_VIEW(listview) ); + GtkTreeIter iter; + + if ( gtk_tree_model_get_iter_from_string( store , &iter , path_string ) == TRUE ) + aud_playlist_set_title (iter_to_row (store, & iter), new_text); + + /* set the renderer uneditable again */ + g_object_set( G_OBJECT(cell) , "editable" , FALSE , NULL ); +} + +static void save_config_cb (void * hook_data, void * user_data) +{ +#if GTK_CHECK_VERSION (2, 18, 0) + if (gtk_widget_get_visible ((GtkWidget *) user_data)) +#else + if (GTK_WIDGET_VISIBLE ((GtkWidget *) user_data)) +#endif + save_position ((GtkWidget *) user_data); +} + +static GtkWidget * playman_win = NULL; + +void +audgui_playlist_manager_ui_show (GtkWidget *mainwin) +{ + GtkWidget *playman_vbox; + GtkWidget * playman_pl_lv, * playman_pl_lv_sw; + GtkCellRenderer *playman_pl_lv_textrndr_name, *playman_pl_lv_textrndr_entriesnum; + GtkTreeViewColumn *playman_pl_lv_col_name, *playman_pl_lv_col_entriesnum; + GtkWidget *playman_bbar_hbbox; + GtkWidget * rename_button, * new_button, * delete_button; + GtkWidget * hbox, * button; + GdkGeometry playman_win_hints; + + if ( playman_win != NULL ) + { + gtk_window_present( GTK_WINDOW(playman_win) ); + return; + } + + playman_win = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_type_hint( GTK_WINDOW(playman_win), GDK_WINDOW_TYPE_HINT_DIALOG ); + gtk_window_set_transient_for( GTK_WINDOW(playman_win) , GTK_WINDOW(mainwin) ); + gtk_window_set_title( GTK_WINDOW(playman_win), _("Playlist Manager") ); + gtk_container_set_border_width ((GtkContainer *) playman_win, 6); + playman_win_hints.min_width = 400; + playman_win_hints.min_height = 250; + gtk_window_set_geometry_hints( GTK_WINDOW(playman_win) , GTK_WIDGET(playman_win) , + &playman_win_hints , GDK_HINT_MIN_SIZE ); + + if (aud_cfg->playlist_manager_width) + { + gtk_window_move ((GtkWindow *) playman_win, aud_cfg->playlist_manager_x, + aud_cfg->playlist_manager_y); + gtk_window_set_default_size ((GtkWindow *) playman_win, + aud_cfg->playlist_manager_width, aud_cfg->playlist_manager_height); + } + + g_signal_connect ((GObject *) playman_win, "delete-event", (GCallback) + hide_cb, NULL); + + playman_vbox = gtk_vbox_new (FALSE, 6); + gtk_container_add( GTK_CONTAINER(playman_win) , playman_vbox ); + + playman_pl_lv = gtk_tree_view_new_with_model (audgui_get_library_store ()); + gtk_tree_view_set_reorderable ((GtkTreeView *) playman_pl_lv, TRUE); + + playman_pl_lv_textrndr_entriesnum = gtk_cell_renderer_text_new(); /* uneditable */ + playman_pl_lv_textrndr_name = gtk_cell_renderer_text_new(); /* can become editable */ + g_object_set( G_OBJECT(playman_pl_lv_textrndr_entriesnum) , "weight-set" , TRUE , NULL ); + g_object_set( G_OBJECT(playman_pl_lv_textrndr_name) , "weight-set" , TRUE , NULL ); + g_signal_connect( G_OBJECT(playman_pl_lv_textrndr_name) , "edited" , + G_CALLBACK(playlist_manager_cb_lv_name_edited) , playman_pl_lv ); + g_object_set_data( G_OBJECT(playman_pl_lv) , "rn" , playman_pl_lv_textrndr_name ); + + playman_pl_lv_col_name = gtk_tree_view_column_new_with_attributes + (_("Playlist"), playman_pl_lv_textrndr_name, "text", + AUDGUI_LIBRARY_STORE_TITLE, "weight", AUDGUI_LIBRARY_STORE_FONT_WEIGHT, + NULL); + gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(playman_pl_lv_col_name) , TRUE ); + gtk_tree_view_append_column( GTK_TREE_VIEW(playman_pl_lv), playman_pl_lv_col_name ); + + playman_pl_lv_col_entriesnum = gtk_tree_view_column_new_with_attributes + (_("Entries"), playman_pl_lv_textrndr_entriesnum, "text", + AUDGUI_LIBRARY_STORE_ENTRY_COUNT, "weight", + AUDGUI_LIBRARY_STORE_FONT_WEIGHT, NULL); + gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(playman_pl_lv_col_entriesnum) , FALSE ); + gtk_tree_view_append_column( GTK_TREE_VIEW(playman_pl_lv), playman_pl_lv_col_entriesnum ); + + playman_pl_lv_sw = gtk_scrolled_window_new( NULL , NULL ); + gtk_scrolled_window_set_shadow_type ((GtkScrolledWindow *) playman_pl_lv_sw, + GTK_SHADOW_IN); + gtk_scrolled_window_set_policy ((GtkScrolledWindow *) playman_pl_lv_sw, + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_container_add( GTK_CONTAINER(playman_pl_lv_sw) , playman_pl_lv ); + gtk_box_pack_start ((GtkBox *) playman_vbox, playman_pl_lv_sw, TRUE, TRUE, 0); + + /* button bar */ + playman_bbar_hbbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout( GTK_BUTTON_BOX(playman_bbar_hbbox) , GTK_BUTTONBOX_END ); + gtk_box_set_spacing ((GtkBox *) playman_bbar_hbbox, 6); + + rename_button = gtk_button_new_with_mnemonic (_("_Rename")); + gtk_button_set_image ((GtkButton *) rename_button, gtk_image_new_from_stock + (GTK_STOCK_EDIT, GTK_ICON_SIZE_BUTTON)); + new_button = gtk_button_new_from_stock (GTK_STOCK_NEW); + delete_button = gtk_button_new_from_stock (GTK_STOCK_DELETE); + + gtk_container_add ((GtkContainer *) playman_bbar_hbbox, rename_button); + gtk_button_box_set_child_secondary ((GtkButtonBox *) playman_bbar_hbbox, + rename_button, TRUE); + gtk_container_add ((GtkContainer *) playman_bbar_hbbox, new_button); + gtk_container_add ((GtkContainer *) playman_bbar_hbbox, delete_button); + + gtk_box_pack_start( GTK_BOX(playman_vbox) , playman_bbar_hbbox , FALSE , FALSE , 0 ); + + g_signal_connect ((GObject *) playman_pl_lv, "row-activated", (GCallback) + activate_cb, playman_win); + g_signal_connect ((GObject *) rename_button, "clicked", (GCallback) + rename_cb, playman_pl_lv); + g_signal_connect ((GObject *) new_button, "clicked", (GCallback) new_cb, + playman_pl_lv); + g_signal_connect ((GObject *) delete_button, "clicked", (GCallback) + delete_cb, playman_pl_lv); + + set_selected_row (playman_pl_lv, aud_playlist_get_active ()); + + hbox = gtk_hbox_new (FALSE, 6); + gtk_box_pack_start ((GtkBox *) playman_vbox, hbox, FALSE, FALSE, 0); + button = gtk_check_button_new_with_mnemonic + (_("_Close dialog on activating playlist")); + gtk_box_pack_start ((GtkBox *) hbox, button, FALSE, FALSE, 0); + audgui_connect_check_box (button, + & aud_cfg->playlist_manager_close_on_activate); + + gtk_widget_show_all( playman_win ); + + aud_hook_associate ("config save", save_config_cb, playman_win); +} + +void audgui_playlist_manager_destroy(void) +{ + if (playman_win) + hide_cb (playman_win); +} diff --git a/src/libaudgui/util.c b/src/libaudgui/util.c new file mode 100644 index 0000000..f2aadbf --- /dev/null +++ b/src/libaudgui/util.c @@ -0,0 +1,127 @@ +/* + * libaudgui/util.c + * Copyright 2010 John Lindgren + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 or version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#include <gdk/gdkkeysyms.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gtk/gtk.h> + +#include "libaudgui.h" +#include "libaudgui-gtk.h" + +void audgui_hide_on_delete (GtkWidget * widget) +{ + g_signal_connect (widget, "delete-event", (GCallback) + gtk_widget_hide_on_delete, NULL); +} + +static gboolean escape_cb (GtkWidget * widget, GdkEventKey * event, void + (* action) (GtkWidget * widget)) +{ + if (event->keyval == GDK_Escape) + { + action (widget); + return TRUE; + } + + return FALSE; +} + +void audgui_hide_on_escape (GtkWidget * widget) +{ + g_signal_connect (widget, "key-press-event", (GCallback) escape_cb, + gtk_widget_hide); +} + +void audgui_destroy_on_escape (GtkWidget * widget) +{ + g_signal_connect (widget, "key-press-event", (GCallback) escape_cb, + gtk_widget_destroy); +} + +static void toggle_cb (GtkToggleButton * toggle, gboolean * setting) +{ + * setting = gtk_toggle_button_get_active (toggle); +} + +void audgui_connect_check_box (GtkWidget * box, gboolean * setting) +{ + gtk_toggle_button_set_active ((GtkToggleButton *) box, * setting); + g_signal_connect ((GObject *) box, "toggled", (GCallback) toggle_cb, setting); +} + +void audgui_simple_message (GtkWidget * * widget, GtkMessageType type, + const gchar * title, const gchar * text) +{ + if (* widget == NULL) + { + * widget = gtk_message_dialog_new (NULL, 0, type, GTK_BUTTONS_OK, "%s", + text); + gtk_window_set_title ((GtkWindow *) * widget, title); + + g_signal_connect (* widget, "response", (GCallback) gtk_widget_destroy, + NULL); + audgui_destroy_on_escape (* widget); + g_signal_connect (* widget, "destroy", (GCallback) gtk_widget_destroyed, + widget); + } + + gtk_window_present ((GtkWindow *) * widget); +} + +GdkPixbuf * audgui_pixbuf_from_data (void * data, gint size) +{ + GdkPixbuf * pixbuf = NULL; + GdkPixbufLoader * loader = gdk_pixbuf_loader_new (); + + if (gdk_pixbuf_loader_write (loader, data, size, NULL)) + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + + gdk_pixbuf_loader_close (loader, NULL); + return pixbuf; +} + +void audgui_pixbuf_scale_within (GdkPixbuf * * pixbuf, gint size) +{ + gint width = gdk_pixbuf_get_width (* pixbuf); + gint height = gdk_pixbuf_get_height (* pixbuf); + GdkPixbuf * pixbuf2; + + if (width > height) + { + height = size * height / width; + width = size; + } + else + { + width = size * width / height; + height = size; + } + + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + pixbuf2 = gdk_pixbuf_scale_simple (* pixbuf, width, height, + GDK_INTERP_BILINEAR); + g_object_unref (* pixbuf); + * pixbuf = pixbuf2; +} diff --git a/src/libaudtag/Makefile b/src/libaudtag/Makefile index 914fa8c..127c8c7 100644 --- a/src/libaudtag/Makefile +++ b/src/libaudtag/Makefile @@ -5,16 +5,14 @@ LIB_MINOR = 0 SRCS = audtag.c \ util.c \ tag_module.c \ - wma/guid.c \ - wma/wma.c \ - id3/id3.c \ - ape/ape.c \ - aac/aac.c -INCLUDES = audtag.h util.h + id3/id3v1.c \ + id3/id3v24.c \ + ape/ape.c + +INCLUDES = audtag.h include ../../buildsys.mk include ../../extra.mk -includesubdir = libaudtag CPPFLAGS += ${LIB_CPPFLAGS} ${GLIB_CFLAGS} ${MOWGLI_CFLAGS} -D_AUDACIOUS_CORE -I.. -I../.. CFLAGS += ${LIB_CFLAGS} diff --git a/src/libaudtag/aac/aac.c b/src/libaudtag/aac/aac.c index 0b04a9e..87f63f9 100644 --- a/src/libaudtag/aac/aac.c +++ b/src/libaudtag/aac/aac.c @@ -1,3 +1,22 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ #include <glib/gstdio.h> #include <libaudcore/tuple.h> @@ -6,60 +25,66 @@ #include "aac.h" #include "../util.h" -static const char* ID3v1GenreList[] = { - "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", - "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", - "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", - "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", - "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", - "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", - "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", - "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", - "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", - "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", - "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", - "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", - "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", - "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", - "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", - "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", - "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", - "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", - "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", - "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", - "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", - "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror", - "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat", - "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary C", - "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", - "SynthPop", +static const char *ID3v1GenreList[] = { + "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", + "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", + "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", + "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", + "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", + "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", + "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", + "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", + "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", + "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", + "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", + "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", + "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", + "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", + "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", + "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", + "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", + "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", + "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", + "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", + "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", + "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror", + "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat", + "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary C", + "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", + "SynthPop", }; -gchar* atom_types[] = {"\251alb", "\251nam", "cprt", "\251art", "\251ART", "trkn", "\251day", "gnre", "desc"}; +gchar *atom_types[] = { "\251alb", "\251nam", "cprt", "\251art", "\251ART", "trkn", "\251day", "gnre", "desc" }; -tag_module_t aac = {aac_can_handle_file, aac_populate_tuple_from_file, aac_write_tuple_to_file}; +Atom *readAtom(VFSFile * fd) +{ + guint32 size = read_BEuint32(fd); + if (size > vfs_fsize(fd)) + return NULL; -Atom *readAtom(VFSFile *fd) { Atom *atom = g_new0(Atom, 1); - atom->size = read_BEuint32(fd); + atom->size = size; atom->name = read_char_data(fd, 4); atom->body = read_char_data(fd, atom->size - 8); atom->type = 0; return atom; } -void writeAtom(VFSFile *fd, Atom *atom) { +void writeAtom(VFSFile * fd, Atom * atom) +{ write_BEuint32(fd, atom->size); vfs_fwrite(atom->name, 4, 1, fd); vfs_fwrite(atom->body, atom->size - 8, 1, fd); } -void printAtom(Atom *atom) { +void printAtom(Atom * atom) +{ AUDDBG("size = %x\n", atom->size); AUDDBG("name = %s\n", atom->name); } -StrDataAtom *readStrDataAtom(VFSFile *fd) { +StrDataAtom *readStrDataAtom(VFSFile * fd) +{ StrDataAtom *atom = g_new0(StrDataAtom, 1); atom->atomsize = read_BEuint32(fd); atom->name = read_char_data(fd, 4); @@ -72,7 +97,8 @@ StrDataAtom *readStrDataAtom(VFSFile *fd) { return atom; } -void writeStrDataAtom(VFSFile *fd, StrDataAtom *atom) { +void writeStrDataAtom(VFSFile * fd, StrDataAtom * atom) +{ write_BEuint32(fd, atom->atomsize); vfs_fwrite(atom->name, 4, 1, fd); write_BEuint32(fd, atom->datasize); @@ -82,7 +108,8 @@ void writeStrDataAtom(VFSFile *fd, StrDataAtom *atom) { vfs_fwrite(atom->data, atom->datasize - 16, 1, fd); } -Atom *findAtom(VFSFile *fd, gchar* name) { +Atom *findAtom(VFSFile * fd, gchar * name) +{ Atom *atom = readAtom(fd); while (strcmp(atom->name, name) && !vfs_feof(fd)) { @@ -98,7 +125,8 @@ Atom *findAtom(VFSFile *fd, gchar* name) { return atom; } -Atom *getilstAtom(VFSFile *fd) { +Atom *getilstAtom(VFSFile * fd) +{ Atom *moov = findAtom(fd, MOOV); // search atom childs @@ -112,8 +140,7 @@ Atom *getilstAtom(VFSFile *fd) { vfs_fseek(fd, -(meta->size - 11), SEEK_CUR); Atom *ilst = findAtom(fd, ILST); - int zz = vfs_ftell(fd); - AUDDBG("zzz = %d\n", zz); + AUDDBG("zzz = %d\n", vfs_ftell(fd)); ilstFileOffset = vfs_ftell(fd) - ilst->size; vfs_fseek(fd, -(ilst->size - 7), SEEK_CUR); @@ -121,7 +148,8 @@ Atom *getilstAtom(VFSFile *fd) { } -int getAtomID(gchar* name) { +int getAtomID(gchar * name) +{ g_return_val_if_fail(name != NULL, -1); int i = 0; for (i = 0; i < MP4_ITEMS_NO; i++) @@ -132,7 +160,8 @@ int getAtomID(gchar* name) { return -1; } -StrDataAtom *makeAtomWithData(const gchar* data, StrDataAtom *atom, int field) { +StrDataAtom *makeAtomWithData(const gchar * data, StrDataAtom * atom, int field) +{ guint32 charsize = strlen(data); atom->atomsize = charsize + 24; atom->name = atom_types[field]; @@ -140,13 +169,14 @@ StrDataAtom *makeAtomWithData(const gchar* data, StrDataAtom *atom, int field) { atom->dataname = "data"; atom->vflag = 0x0; atom->nullData = 0x0; - atom->data = (gchar*) data; + atom->data = (gchar *) data; atom->type = 1; return atom; } -void writeAtomListToFile(VFSFile* from, VFSFile *to, int offset, mowgli_list_t *list) { +void writeAtomListToFile(VFSFile * from, VFSFile * to, int offset, mowgli_list_t * list) +{ //read free atom if we have any :D guint32 oset = ilstFileOffset + ilstAtom->size; vfs_fseek(from, oset, SEEK_SET); @@ -174,13 +204,15 @@ void writeAtomListToFile(VFSFile* from, VFSFile *to, int offset, mowgli_list_t * mowgli_node_t *n, *tn; - MOWGLI_LIST_FOREACH_SAFE(n, tn, list->head) { - if (((Atom*) (n->data))->type == 0) + MOWGLI_LIST_FOREACH_SAFE(n, tn, list->head) + { + if (((Atom *) (n->data))->type == 0) { - writeAtom(to, (Atom*) (n->data)); - } else + writeAtom(to, (Atom *) (n->data)); + } + else { - writeStrDataAtom(to, (StrDataAtom*) (n->data)); + writeStrDataAtom(to, (StrDataAtom *) (n->data)); } } @@ -188,8 +220,9 @@ void writeAtomListToFile(VFSFile* from, VFSFile *to, int offset, mowgli_list_t * if (atoms_before_free->count != 0) { - MOWGLI_LIST_FOREACH_SAFE(n, tn, list->head) { - writeAtom(to, (Atom*) (n->data)); + MOWGLI_LIST_FOREACH_SAFE(n, tn, list->head) + { + writeAtom(to, (Atom *) (n->data)); } } if (atom != NULL) @@ -199,14 +232,18 @@ void writeAtomListToFile(VFSFile* from, VFSFile *to, int offset, mowgli_list_t * writeAtom(to, atom); } -gboolean aac_can_handle_file(VFSFile *f) { +gboolean aac_can_handle_file(VFSFile * f) +{ Atom *first_atom = readAtom(f); + if (first_atom == NULL) + return FALSE; if (!strcmp(first_atom->name, FTYP)) return TRUE; return FALSE; } -Tuple *aac_populate_tuple_from_file(Tuple *tuple, VFSFile *f) { +gboolean aac_read_tag (Tuple * tuple, VFSFile * f) +{ if (ilstAtom) g_free(ilstAtom); ilstAtom = getilstAtom(f); @@ -216,7 +253,8 @@ Tuple *aac_populate_tuple_from_file(Tuple *tuple, VFSFile *f) { { mowgli_node_t *n, *tn; - MOWGLI_LIST_FOREACH_SAFE(n, tn, dataAtoms->head) { + MOWGLI_LIST_FOREACH_SAFE(n, tn, dataAtoms->head) + { mowgli_node_delete(n, dataAtoms); } } @@ -239,55 +277,57 @@ Tuple *aac_populate_tuple_from_file(Tuple *tuple, VFSFile *f) { switch (atomtype) { - case MP4_ALBUM: - { - tuple_associate_string(tuple, FIELD_ALBUM, NULL, a->data); - } - break; - case MP4_TITLE: - { - tuple_associate_string(tuple, FIELD_TITLE, NULL, a->data); - } - break; - case MP4_COPYRIGHT: - { - tuple_associate_string(tuple, FIELD_COPYRIGHT, NULL, a->data); - } - break; - case MP4_ARTIST: - case MP4_ARTIST2: - { - tuple_associate_string(tuple, FIELD_ARTIST, NULL, a->data); - } - break; - case MP4_TRACKNR: - { - //tuple_associate_string(tuple,FIELD_ALBUM,NULL,a->data); - } - break; - case MP4_YEAR: - { - tuple_associate_int(tuple, FIELD_YEAR, NULL, atoi(a->data)); - } - break; - case MP4_GENRE: - { - guint8 *val = (guint8*) (a->data + (a->datasize - 17)); - const gchar* genre = ID3v1GenreList[*val - 1]; - tuple_associate_string(tuple, FIELD_GENRE, NULL, genre); - } - break; - case MP4_COMMENT: - { - tuple_associate_string(tuple, FIELD_COMMENT, NULL, a->data); - } - break; + case MP4_ALBUM: + { + tuple_associate_string(tuple, FIELD_ALBUM, NULL, a->data); + } + break; + case MP4_TITLE: + { + tuple_associate_string(tuple, FIELD_TITLE, NULL, a->data); + } + break; + case MP4_COPYRIGHT: + { + tuple_associate_string(tuple, FIELD_COPYRIGHT, NULL, a->data); + } + break; + case MP4_ARTIST: + case MP4_ARTIST2: + { + tuple_associate_string(tuple, FIELD_ARTIST, NULL, a->data); + } + break; + case MP4_TRACKNR: + { + //tuple_associate_string(tuple,FIELD_ALBUM,NULL,a->data); + } + break; + case MP4_YEAR: + { + tuple_associate_int(tuple, FIELD_YEAR, NULL, atoi(a->data)); + } + break; + case MP4_GENRE: + { + guint8 *val = (guint8 *) (a->data + (a->datasize - 17)); + const gchar *genre = ID3v1GenreList[*val - 1]; + tuple_associate_string(tuple, FIELD_GENRE, NULL, genre); + } + break; + case MP4_COMMENT: + { + tuple_associate_string(tuple, FIELD_COMMENT, NULL, a->data); + } + break; } } - return tuple; + + return TRUE; } -gboolean aac_write_tuple_to_file(Tuple* tuple, VFSFile *f) { +gboolean aac_write_tag (Tuple * tuple, VFSFile * f) +{ #ifdef BROKEN return FALSE; #endif @@ -296,129 +336,136 @@ gboolean aac_write_tuple_to_file(Tuple* tuple, VFSFile *f) { mowgli_list_t *newdataAtoms; newdataAtoms = mowgli_list_create(); - MOWGLI_LIST_FOREACH_SAFE(n, tn, dataAtoms->head) { - int atomtype = getAtomID(((StrDataAtom*) (n->data))->name); + MOWGLI_LIST_FOREACH_SAFE(n, tn, dataAtoms->head) + { + int atomtype = getAtomID(((StrDataAtom *) (n->data))->name); switch (atomtype) { - case MP4_ALBUM: - { - const gchar* strVal = tuple_get_string(tuple, FIELD_ALBUM, NULL); - if (strVal != NULL) - { - StrDataAtom *atom = g_new0(StrDataAtom, 1); - atom = makeAtomWithData(strVal, atom, MP4_ALBUM); - mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); - newilstSize += atom->atomsize; - } else - { - mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); - newilstSize += ((Atom*) (n->data))->size; - } - } - break; - case MP4_TITLE: - { - const gchar* strVal = tuple_get_string(tuple, FIELD_TITLE, NULL); - if (strVal != NULL) - { - StrDataAtom *atom = g_new0(StrDataAtom, 1); - atom = makeAtomWithData(strVal, atom, MP4_TITLE); - mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); - newilstSize += atom->atomsize; - } else - { - mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); - newilstSize += ((Atom*) (n->data))->size; - } - } - break; - case MP4_COPYRIGHT: - { - const gchar* strVal = tuple_get_string(tuple, FIELD_COPYRIGHT, NULL); - if (strVal != NULL) - { - StrDataAtom *atom = g_new0(StrDataAtom, 1); - atom = makeAtomWithData(strVal, atom, MP4_COPYRIGHT); - mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); - newilstSize += atom->atomsize; - } else - { - mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); - newilstSize += ((Atom*) (n->data))->size; - } - } - break; - case MP4_ARTIST: - case MP4_ARTIST2: - { - const gchar* strVal = tuple_get_string(tuple, FIELD_ARTIST, NULL); - if (strVal != NULL) - { - StrDataAtom *atom = g_new0(StrDataAtom, 1); - atom = makeAtomWithData(strVal, atom, MP4_ARTIST2); - mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); - newilstSize += atom->atomsize; - } else - { - mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); - newilstSize += ((Atom*) (n->data))->size; - } - } - break; - case MP4_TRACKNR: - { - //tuple_associate_string(tuple,FIELD_ALBUM,NULL,a->data); - } - break; - case MP4_YEAR: - { - int iyear = tuple_get_int(tuple, FIELD_YEAR, NULL); - gchar* strVal = g_strdup_printf("%d", iyear); - if (strVal != NULL) - { - StrDataAtom *atom = g_new0(StrDataAtom, 1); - atom = makeAtomWithData(strVal, atom, MP4_YEAR); - mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); - newilstSize += atom->atomsize; - } else - { - mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); - newilstSize += ((Atom*) (n->data))->size; - } - } - break; - /* - case MP4_GENRE: - { - - guint8 *val = (guint8*)(a->data + (a->datasize-17)); - const gchar* genre = ID3v1GenreList[*val-1]; - tuple_associate_string(tuple,FIELD_GENRE,NULL,genre); - - }break; - */ - case MP4_COMMENT: - { - const gchar* strVal = tuple_get_string(tuple, FIELD_COMMENT, NULL); - if (strVal != NULL) - { - StrDataAtom *atom = g_new0(StrDataAtom, 1); - atom = makeAtomWithData(strVal, atom, MP4_COMMENT); - mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); - newilstSize += atom->atomsize; - } else - { - mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); - newilstSize += ((Atom*) (n->data))->size; - } - } - break; - default: - { - mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); - newilstSize += ((Atom*) (n->data))->size; - } - break; + case MP4_ALBUM: + { + const gchar *strVal = tuple_get_string(tuple, FIELD_ALBUM, NULL); + if (strVal != NULL) + { + StrDataAtom *atom = g_new0(StrDataAtom, 1); + atom = makeAtomWithData(strVal, atom, MP4_ALBUM); + mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); + newilstSize += atom->atomsize; + } + else + { + mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); + newilstSize += ((Atom *) (n->data))->size; + } + } + break; + case MP4_TITLE: + { + const gchar *strVal = tuple_get_string(tuple, FIELD_TITLE, NULL); + if (strVal != NULL) + { + StrDataAtom *atom = g_new0(StrDataAtom, 1); + atom = makeAtomWithData(strVal, atom, MP4_TITLE); + mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); + newilstSize += atom->atomsize; + } + else + { + mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); + newilstSize += ((Atom *) (n->data))->size; + } + } + break; + case MP4_COPYRIGHT: + { + const gchar *strVal = tuple_get_string(tuple, FIELD_COPYRIGHT, NULL); + if (strVal != NULL) + { + StrDataAtom *atom = g_new0(StrDataAtom, 1); + atom = makeAtomWithData(strVal, atom, MP4_COPYRIGHT); + mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); + newilstSize += atom->atomsize; + } + else + { + mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); + newilstSize += ((Atom *) (n->data))->size; + } + } + break; + case MP4_ARTIST: + case MP4_ARTIST2: + { + const gchar *strVal = tuple_get_string(tuple, FIELD_ARTIST, NULL); + if (strVal != NULL) + { + StrDataAtom *atom = g_new0(StrDataAtom, 1); + atom = makeAtomWithData(strVal, atom, MP4_ARTIST2); + mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); + newilstSize += atom->atomsize; + } + else + { + mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); + newilstSize += ((Atom *) (n->data))->size; + } + } + break; + case MP4_TRACKNR: + { + //tuple_associate_string(tuple,FIELD_ALBUM,NULL,a->data); + } + break; + case MP4_YEAR: + { + int iyear = tuple_get_int(tuple, FIELD_YEAR, NULL); + gchar *strVal = g_strdup_printf("%d", iyear); + if (strVal != NULL) + { + StrDataAtom *atom = g_new0(StrDataAtom, 1); + atom = makeAtomWithData(strVal, atom, MP4_YEAR); + mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); + newilstSize += atom->atomsize; + } + else + { + mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); + newilstSize += ((Atom *) (n->data))->size; + } + } + break; + /* + case MP4_GENRE: + { + + guint8 *val = (guint8*)(a->data + (a->datasize-17)); + const gchar* genre = ID3v1GenreList[*val-1]; + tuple_associate_string(tuple,FIELD_GENRE,NULL,genre); + + }break; + */ + case MP4_COMMENT: + { + const gchar *strVal = tuple_get_string(tuple, FIELD_COMMENT, NULL); + if (strVal != NULL) + { + StrDataAtom *atom = g_new0(StrDataAtom, 1); + atom = makeAtomWithData(strVal, atom, MP4_COMMENT); + mowgli_node_add(atom, mowgli_node_create(), newdataAtoms); + newilstSize += atom->atomsize; + } + else + { + mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); + newilstSize += ((Atom *) (n->data))->size; + } + } + break; + default: + { + mowgli_node_add(n->data, mowgli_node_create(), newdataAtoms); + newilstSize += ((Atom *) (n->data))->size; + } + break; } } diff --git a/src/libaudtag/aac/aac.h b/src/libaudtag/aac/aac.h index 7d2d1f2..8f4d57d 100644 --- a/src/libaudtag/aac/aac.h +++ b/src/libaudtag/aac/aac.h @@ -1,3 +1,23 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + #ifndef AAC_H #define AAC_H #include <libaudcore/tuple.h> @@ -46,21 +66,21 @@ typedef struct strdataatom int type; }StrDataAtom; - - -gboolean aac_can_handle_file(VFSFile *f); - -Tuple *aac_populate_tuple_from_file(Tuple *tuple,VFSFile *f); - -gboolean aac_write_tuple_to_file(Tuple* tuple, VFSFile *f); - -extern tag_module_t aac; - Atom *ilstAtom; guint64 ilstFileOffset; guint32 newilstSize ; mowgli_list_t *dataAtoms; mowgli_dictionary_t *ilstAtoms; -#endif +/* TAG plugin API */ +gboolean aac_can_handle_file(VFSFile *f); +gboolean aac_read_tag (Tuple * tuple, VFSFile * handle); +gboolean aac_write_tag (Tuple * tuple, VFSFile * handle); +static const tag_module_t aac = { + .name = "AAC", + .can_handle_file = aac_can_handle_file, + .read_tag = aac_read_tag, + .write_tag = aac_write_tag, +}; +#endif diff --git a/src/libaudtag/ape/ape.c b/src/libaudtag/ape/ape.c index 46d45cc..548ac92 100755 --- a/src/libaudtag/ape/ape.c +++ b/src/libaudtag/ape/ape.c @@ -1,298 +1,505 @@ +/* + * Copyright 2010 John Lindgren + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +/* TODO: + * - Support updating files that have their tag at the beginning? + */ + #include <glib.h> -#include <glib/gstdio.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libaudcore/vfs.h> + #include "ape.h" -#include "../util.h" -#include <inttypes.h> -#include "../tag_module.h" -#define APE_IDENTIFIER "APETAGEX" +#pragma pack(push) /* must be byte-aligned */ +#pragma pack(1) +typedef struct +{ + gchar magic[8]; + guint32 version; /* LE */ + guint32 length; /* LE */ + guint32 items; /* LE */ + guint32 flags; /* LE */ + guint64 reserved; +} +APEHeader; +#pragma pack(pop) -tag_module_t ape = {ape_can_handle_file, ape_populate_tuple_from_file, ape_write_tuple_to_file}; +typedef struct +{ + gchar * key, * value; +} +ValuePair; -gchar* ape_items[] = {"Album", "Title", "Copyright", "Artist", "Track", "Year", "Genre", "Comment"}; +#define APE_FLAG_HAS_HEADER (1 << 31) +#define APE_FLAG_HAS_NO_FOOTER (1 << 30) +#define APE_FLAG_IS_HEADER (1 << 29) -/* reading fucntions */ +static gboolean ape_read_header (VFSFile * handle, APEHeader * header) +{ + if (vfs_fread (header, 1, sizeof (APEHeader), handle) != sizeof (APEHeader)) + return FALSE; + if (strncmp (header->magic, "APETAGEX", 8)) + return FALSE; -APEv2Header *readAPEHeader(VFSFile *fd) { - APEv2Header *header = g_new0(APEv2Header, 1); - header->preamble = read_char_data(fd, 8); - header->version = read_LEuint32(fd); - header->tagSize = read_LEuint32(fd); - header->itemCount = read_LEuint32(fd); - header->reserved = read_LEuint64(fd); - return header; -} + header->version = GUINT32_FROM_LE (header->version); + header->length = GUINT32_FROM_LE (header->length); + header->items = GUINT32_FROM_LE (header->items); + header->flags = GUINT32_FROM_LE (header->flags); -gchar* read_NULLterminatedString(VFSFile *fd) { - gchar buf[1024]; - gchar ch; - int size = 0; - while (1) { - vfs_fread(&ch, 1, 1, fd); - if (ch != 0) { - buf[size] = ch; - size++; - } else - break; - } - gchar* ret = g_strndup(buf, size); + if (header->length < sizeof (APEHeader)) + return FALSE; - return ret; + return TRUE; } -gchar* readUTF_8(VFSFile *fd, int size) { - gchar *buf = g_new0(gchar, size); - vfs_fread(buf, size, 1, fd); - return buf; -} +static gboolean ape_find_header (VFSFile * handle, APEHeader * header, gint * + start, gint * length, gint * data_start, gint * data_length) +{ + APEHeader secondary; -APETagItem *readAPETagItem(VFSFile *fd) { - APETagItem *tagitem = g_new0(APETagItem, 1); - tagitem->size = read_LEuint32(fd); - tagitem->flags = read_LEuint32(fd); - tagitem->key = read_NULLterminatedString(fd); - tagitem->value = readUTF_8(fd, tagitem->size); + if (vfs_fseek (handle, 0, SEEK_SET)) + return FALSE; - return tagitem; -} + if (ape_read_header (handle, header)) + { + AUDDBG ("Found header at 0, length = %d, version = %d.\n", (gint) + header->length, (gint) header->version); + * start = 0; + * length = header->length; + * data_start = sizeof (APEHeader); + * data_length = header->length - sizeof (APEHeader); + + if (! (header->flags & APE_FLAG_HAS_HEADER) || ! (header->flags & + APE_FLAG_IS_HEADER)) + { + AUDDBG ("Invalid header flags (%u).\n", (guint) header->flags); + return FALSE; + } + + if (! (header->flags & APE_FLAG_HAS_NO_FOOTER)) + { + if (vfs_fseek (handle, header->length, SEEK_CUR)) + return FALSE; + + if (! ape_read_header (handle, & secondary)) + { + AUDDBG ("Expected footer, but found none.\n"); + return FALSE; + } + + * length += sizeof (APEHeader); + } + + return TRUE; + } -//writing functions + if (vfs_fseek (handle, -sizeof (APEHeader), SEEK_END)) + return FALSE; -void write_tagItemToFile(VFSFile *fd, APETagItem *item) { - item->size -=1; - vfs_fwrite(&item->size, 4, 1, fd); - vfs_fwrite(&item->flags, 4, 1, fd); - vfs_fwrite(item->key, strlen(item->key) +1, 1, fd); - vfs_fwrite(item->value, item->size, 1, fd); + if (ape_read_header (handle, header)) + { + AUDDBG ("Found footer at %d, length = %d, version = %d.\n", (gint) + vfs_ftell (handle) - (gint) sizeof (APEHeader), (gint) header->length, + (gint) header->version); + * start = vfs_ftell (handle) - header->length; + * length = header->length; + * data_start = vfs_ftell (handle) - header->length; + * data_length = header->length - sizeof (APEHeader); + + if ((header->flags & APE_FLAG_HAS_NO_FOOTER) || (header->flags & + APE_FLAG_IS_HEADER)) + { + AUDDBG ("Invalid footer flags (%u).\n", (guint) header->flags); + return FALSE; + } + + if (header->flags & APE_FLAG_HAS_HEADER) + { + if (vfs_fseek (handle, -(gint) header->length - sizeof (APEHeader), + SEEK_CUR)) + return FALSE; + + if (! ape_read_header (handle, & secondary)) + { + AUDDBG ("Expected header, but found none.\n"); + return FALSE; + } + + * start -= sizeof (APEHeader); + * length += sizeof (APEHeader); + } + + return TRUE; + } + + AUDDBG ("No header found.\n"); + return FALSE; } -void write_apeHeaderToFile(VFSFile *fd, APEv2Header *header) { - vfs_fwrite(header->preamble, 8, 1, fd); - vfs_fwrite(&header->version, 4, 1, fd); - vfs_fwrite(&header->tagSize, 4, 1, fd); - vfs_fwrite(&header->itemCount, 4, 1, fd); - vfs_fwrite(&header->flags, 4, 1, fd); - vfs_fwrite(&header->reserved, 8, 1, fd); +static gboolean ape_is_our_file (VFSFile * handle) +{ + APEHeader header; + gint start, length, data_start, data_length; + + return ape_find_header (handle, & header, & start, & length, & data_start, + & data_length); } -void write_allTagsToFile(VFSFile *fd, APEv2Header *header) { - mowgli_node_t *n, *tn; +static ValuePair * ape_read_item (void * * data, gint length) +{ + guint32 * header = * data; + gchar * value; + ValuePair * pair; - MOWGLI_LIST_FOREACH_SAFE(n, tn, tagKeys->head) { - APETagItem *tagItem = (APETagItem*) mowgli_dictionary_retrieve(tagItems, (gchar*) (n->data)); - write_tagItemToFile(fd, tagItem); + if (length < 8) + { + AUDDBG ("Expected item, but only %d bytes remain in tag.\n", length); + return NULL; } -} -APEv2Header *computeNewHeader() { - guint32 size = 0; - mowgli_node_t *n, *tn; - APEv2Header *header = g_new0(APEv2Header, 1); + value = memchr ((gchar *) (* data) + 8, 0, length - 8); - MOWGLI_LIST_FOREACH_SAFE(n, tn, tagKeys->head) { - APETagItem *tagItem = (APETagItem*) mowgli_dictionary_retrieve(tagItems, (gchar*) (n->data)); - size += (tagItem->size + 4 + 4 + strlen(tagItem->key)); + if (value == NULL) + { + AUDDBG ("Unterminated item key (max length = %d).\n", length - 8); + return NULL; } - header->flags = 0; - header->preamble = APE_IDENTIFIER; - header->reserved = 0; - header->version = 2000; - header->itemCount = tagKeys->count; - header->tagSize = size + 32 ; //(32 - the size of the footer) - - return header; -} -int getTagItemID(APETagItem *tagitem) { - int i = 0; - for (i = 0; i < APE_ITEMS_NO; i++) { - if (!g_utf8_collate(tagitem->key, ape_items[i])) - return i; + value ++; + + if (header[0] > (gchar *) (* data) + length - value) + { + AUDDBG ("Item value of length %d, but only %d bytes remain in tag.\n", + (gint) header[0], (gint) ((gchar *) (* data) + length - value)); + return NULL; } - return -1; -} -gboolean tagContainsHeader(APEv2Header *header) { - return (header->flags & 0x0001); + pair = g_malloc (sizeof (ValuePair)); + pair->key = g_strdup ((gchar *) (* data) + 8); + pair->value = g_strndup (value, header[0]); + + * data = value + header[0]; + + return pair; } -void add_tagItemFromTuple(Tuple *tuple, int tuple_field, int ape_field) { - gboolean new = FALSE; - APETagItem *tagItem = (APETagItem*) mowgli_dictionary_retrieve(tagItems, ape_items[ape_field]); - if (tagItem == NULL) { - tagItem = g_new0(APETagItem, 1); - new = TRUE; +static GList * ape_read_items (VFSFile * handle) +{ + GList * list = NULL; + APEHeader header; + gint start, length, data_start, data_length; + void * data, * item; + + if (! ape_find_header (handle, & header, & start, & length, & data_start, + & data_length)) + return NULL; + + if (vfs_fseek (handle, data_start, SEEK_SET)) + return NULL; + + data = g_malloc (data_length); + + if (vfs_fread (data, 1, data_length, handle) != data_length) + { + g_free (data); + return NULL; + } + + AUDDBG ("Reading %d items:\n", header.items); + item = data; + + while (header.items --) + { + ValuePair * pair = ape_read_item (& item, (gchar *) data + data_length - + (gchar *) item); + + if (pair == NULL) + break; + + AUDDBG ("Read: %s = %s.\n", pair->key, pair->value); + list = g_list_prepend (list, pair); } - gchar* value = 0; - if (tuple_get_value_type(tuple, tuple_field, NULL) == TUPLE_STRING) - value = g_strdup(tuple_get_string(tuple, tuple_field, NULL)); - if (tuple_get_value_type(tuple, tuple_field, NULL) == TUPLE_INT) - value = g_strdup_printf("%d", tuple_get_int(tuple, tuple_field, NULL)); - - tagItem->flags = 0; - tagItem->key = g_strdup(ape_items[ape_field]); - tagItem->value = value; - tagItem->size = strlen(value) + 1; - if (new) { - mowgli_node_add(tagItem->key, mowgli_node_create(), tagKeys); - mowgli_dictionary_add(tagItems, tagItem->key, tagItem); + + g_free (data); + return g_list_reverse (list); +} + +static void free_tag_list (GList * list) +{ + while (list != NULL) + { + g_free (((ValuePair *) list->data)->key); + g_free (((ValuePair *) list->data)->value); + g_free (list->data); + list = g_list_delete_link (list, list); } } +static void parse_gain_text (const gchar * text, gint * value, gint * unit) +{ + gint sign = 1; + * value = 0; + * unit = 1; -gboolean ape_can_handle_file(VFSFile *f) { - APEv2Header *header = readAPEHeader(f); - if (!strcmp(header->preamble, APE_IDENTIFIER)) - return TRUE; - else { - //maybe the tag is at the end of the file - guint64 filesize = vfs_fsize(f); - vfs_fseek(f, filesize-32, SEEK_SET); - APEv2Header *header = readAPEHeader(f); - if (!strcmp(header->preamble, APE_IDENTIFIER)) - return TRUE; + if (* text == '-') + { + sign = -1; + text ++; } - return FALSE; -} -Tuple *ape_populate_tuple_from_file(Tuple *tuple, VFSFile *f) { - int i; - vfs_fseek(f, 0, SEEK_SET); - headerPosition = 0; - guint64 filesize = vfs_fsize(f); - APEv2Header *header = readAPEHeader(f); - if (strcmp(header->preamble, APE_IDENTIFIER)) { - g_free(header); - //maybe the tag is at the end of the file - vfs_fseek(f, filesize-32, SEEK_SET); - header = readAPEHeader(f); - if (!strcmp(header->preamble, APE_IDENTIFIER)) { - //read all the items from the end of the file - // if(tagContainsHeader(header)) - gchar* path = g_strdup(f->uri); - vfs_fclose(f); - f = vfs_fopen(path,"r"); - long offset = filesize - (header->tagSize); - vfs_fseek(f, offset, SEEK_SET); - headerPosition = vfs_ftell(f); - // else vfs_fseek(f,-(header->tagSize),SEEK_END); - } else - return NULL; - } else - return NULL; - if(tagKeys != NULL) + while (* text >= '0' && * text <= '9') + { + * value = * value * 10 + (* text - '0'); + text ++; + } + + if (* text == '.') { - mowgli_node_t *n, *tn; - MOWGLI_LIST_FOREACH_SAFE(n, tn, tagKeys->head) + text ++; + + while (* text >= '0' && * text <= '9' && * value < G_MAXINT / 10) { - mowgli_node_delete(n,tagKeys); + * value = * value * 10 + (* text - '0'); + * unit = * unit * 10; + text ++; } } - tagKeys = mowgli_list_create(); - tagItems = mowgli_dictionary_create(strcasecmp); - for (i = 0; i < header->itemCount; i++) { - APETagItem *tagitem = readAPETagItem(f); - int tagid = getTagItemID(tagitem); - mowgli_node_add(tagitem->key, mowgli_node_create(), tagKeys); - mowgli_dictionary_add(tagItems, tagitem->key, tagitem); - - switch (tagid) { - case APE_ALBUM: - { - tuple_associate_string(tuple, FIELD_ALBUM, NULL, tagitem->value); - } - break; - case APE_TITLE: - { - tuple_associate_string(tuple, FIELD_TITLE, NULL, tagitem->value); - } - break; - case APE_COPYRIGHT: - { - tuple_associate_string(tuple, FIELD_COPYRIGHT, NULL, tagitem->value); - } - break; - case APE_ARTIST: - { - tuple_associate_string(tuple, FIELD_ARTIST, NULL, tagitem->value); - } - break; - case APE_TRACKNR: - { - tuple_associate_int(tuple, FIELD_TRACK_NUMBER, NULL, atoi(tagitem->value)); - } - break; - case APE_YEAR: - { - tuple_associate_int(tuple, FIELD_YEAR, NULL, atoi(tagitem->value)); - } - break; - case APE_GENRE: - { - tuple_associate_string(tuple, FIELD_GENRE, NULL, tagitem->value); - } - break; - case APE_COMMENT: - { - tuple_associate_string(tuple, FIELD_COMMENT, NULL, tagitem->value); - } - break; - } + * value = * value * sign; +} + +static void set_gain_info (Tuple * tuple, gint field, gint unit_field, + const gchar * text) +{ + gint value, unit; + + parse_gain_text (text, & value, & unit); + + if (tuple_get_value_type (tuple, unit_field, NULL) == TUPLE_INT) + value = value * (gint64) tuple_get_int (tuple, unit_field, NULL) / unit; + else + tuple_associate_int (tuple, unit_field, NULL, unit); + + tuple_associate_int (tuple, field, NULL, value); +} + +static gboolean ape_read_tag (Tuple * tuple, VFSFile * handle) +{ + GList * list = ape_read_items (handle), * node; + + for (node = list; node != NULL; node = node->next) + { + gchar * key = ((ValuePair *) node->data)->key; + gchar * value = ((ValuePair *) node->data)->value; + + if (! strcmp (key, "Artist")) + tuple_associate_string (tuple, FIELD_ARTIST, NULL, value); + else if (! strcmp (key, "Title")) + tuple_associate_string (tuple, FIELD_TITLE, NULL, value); + else if (! strcmp (key, "Album")) + tuple_associate_string (tuple, FIELD_ALBUM, NULL, value); + else if (! strcmp (key, "Comment")) + tuple_associate_string (tuple, FIELD_COMMENT, NULL, value); + else if (! strcmp (key, "Genre")) + tuple_associate_string (tuple, FIELD_GENRE, NULL, value); + else if (! strcmp (key, "Track")) + tuple_associate_int (tuple, FIELD_TRACK_NUMBER, NULL, atoi (value)); + else if (! strcmp (key, "Year")) + tuple_associate_int (tuple, FIELD_YEAR, NULL, atoi (value)); + else if (! strcasecmp (key, "REPLAYGAIN_TRACK_GAIN")) + set_gain_info (tuple, FIELD_GAIN_TRACK_GAIN, FIELD_GAIN_GAIN_UNIT, + value); + else if (! strcasecmp (key, "REPLAYGAIN_TRACK_PEAK")) + set_gain_info (tuple, FIELD_GAIN_TRACK_PEAK, FIELD_GAIN_PEAK_UNIT, + value); + else if (! strcasecmp (key, "REPLAYGAIN_ALBUM_GAIN")) + set_gain_info (tuple, FIELD_GAIN_ALBUM_GAIN, FIELD_GAIN_GAIN_UNIT, + value); + else if (! strcasecmp (key, "REPLAYGAIN_ALBUM_PEAK")) + set_gain_info (tuple, FIELD_GAIN_ALBUM_PEAK, FIELD_GAIN_PEAK_UNIT, + value); } - return tuple; + + free_tag_list (list); + return TRUE; } -gboolean ape_write_tuple_to_file(Tuple* tuple, VFSFile *f) +static gboolean ape_write_item (VFSFile * handle, const gchar * key, + const gchar * value, int * written_length) { - VFSFile *tmp; - const gchar *tmpdir = g_get_tmp_dir(); - gchar *tmp_path = g_strdup_printf("file://%s/%s", tmpdir, "tmp.mpc"); - tmp = vfs_fopen(tmp_path, "w+"); + gint key_len = strlen (key) + 1; + gint value_len = strlen (value); + guint32 header[2]; + AUDDBG ("Write: %s = %s.\n", key, value); - if (tuple_get_string(tuple, FIELD_ARTIST, NULL)) - add_tagItemFromTuple(tuple, FIELD_ARTIST, APE_ARTIST); + header[0] = GUINT32_TO_LE (value_len); + header[1] = 0; - if (tuple_get_string(tuple, FIELD_TITLE, NULL)) - add_tagItemFromTuple(tuple, FIELD_TITLE, APE_TITLE); + if (vfs_fwrite (header, 1, 8, handle) != 8) + return FALSE; + if (vfs_fwrite (key, 1, key_len, handle) != key_len) + return FALSE; - if (tuple_get_string(tuple, FIELD_ALBUM, NULL)) - add_tagItemFromTuple(tuple, FIELD_ALBUM, APE_ALBUM); + if (vfs_fwrite (value, 1, value_len, handle) != value_len) + return FALSE; - if (tuple_get_string(tuple, FIELD_COMMENT, NULL)) - add_tagItemFromTuple(tuple, FIELD_COMMENT, APE_COMMENT); + * written_length += 8 + key_len + value_len; + return TRUE; +} - if (tuple_get_string(tuple, FIELD_GENRE, NULL)) - add_tagItemFromTuple(tuple, FIELD_GENRE, APE_GENRE); +static gboolean write_string_item (Tuple * tuple, int field, VFSFile * handle, + const gchar * key, int * written_length, int * written_items) +{ + const gchar * value = tuple_get_string (tuple, field, NULL); - if (tuple_get_int(tuple, FIELD_YEAR, NULL) != -1) - add_tagItemFromTuple(tuple, FIELD_YEAR, APE_YEAR); + if (value == NULL) + return TRUE; - if(tuple_get_int(tuple,FIELD_TRACK_NUMBER,NULL) != -1) - add_tagItemFromTuple(tuple, FIELD_TRACK_NUMBER, APE_TRACKNR); + if (! ape_write_item (handle, key, value, written_length)) + return FALSE; - copyAudioData(f,tmp,0,headerPosition); + (* written_items) ++; + return TRUE; +} - APEv2Header *header = computeNewHeader(); - write_apeHeaderToFile(tmp, header); +static gboolean write_integer_item (Tuple * tuple, int field, VFSFile * handle, + const gchar * key, int * written_length, int * written_items) +{ + gint value = tuple_get_int (tuple, field, NULL); + gchar scratch[32]; - write_allTagsToFile(tmp, header); - write_apeHeaderToFile(tmp, header); + if (! value) + return TRUE; + snprintf (scratch, sizeof scratch, "%d", value); - gchar *uri = g_strdup(f -> uri); - vfs_fclose(tmp); - gchar* f1 = g_filename_from_uri(tmp_path,NULL,NULL); - gchar* f2 = g_filename_from_uri(uri,NULL,NULL); - if (g_rename(f1,f2 ) == 0) { - AUDDBG("the tag was updated successfully\n"); - } else { - AUDDBG("an error has occured\n"); + if (! ape_write_item (handle, key, scratch, written_length)) + return FALSE; + + (* written_items) ++; + return TRUE; +} + +static gboolean write_header (gint data_length, gint items, gboolean is_header, + VFSFile * handle) +{ + APEHeader header; + + memcpy (header.magic, "APETAGEX", 8); + header.version = GUINT32_TO_LE (2000); + header.length = GUINT32_TO_LE (data_length + sizeof (APEHeader)); + header.items = GUINT32_TO_LE (items); + header.flags = is_header ? GUINT32_TO_LE (APE_FLAG_HAS_HEADER | + APE_FLAG_IS_HEADER) : GUINT32_TO_LE (APE_FLAG_HAS_HEADER); + header.reserved = 0; + + return vfs_fwrite (& header, 1, sizeof (APEHeader), handle) == sizeof + (APEHeader); +} + +static gboolean ape_write_tag (Tuple * tuple, VFSFile * handle) +{ + GList * list = ape_read_items (handle), * node; + APEHeader header; + gint start, length, data_start, data_length, items; + + if (ape_find_header (handle, & header, & start, & length, & data_start, + & data_length)) + { + if (start + length != vfs_fsize (handle)) + { + AUDDBG ("Writing tags is only supported at end of file.\n"); + goto ERROR; + } + + if (vfs_ftruncate (handle, start)) + goto ERROR; + } + else + { + start = vfs_fsize (handle); + + if (start < 0) + goto ERROR; + } + + if (vfs_fseek (handle, start, SEEK_SET) || ! write_header (0, 0, TRUE, + handle)) + goto ERROR; + + length = 0; + items = 0; + + if (! write_string_item (tuple, FIELD_ARTIST, handle, "Artist", & length, + & items) || ! write_string_item (tuple, FIELD_TITLE, handle, "Title", + & length, & items) || ! write_string_item (tuple, FIELD_ALBUM, handle, + "Album", & length, & items) || ! write_string_item (tuple, FIELD_COMMENT, + handle, "Comment", & length, & items) || ! write_string_item (tuple, + FIELD_GENRE, handle, "Genre", & length, & items) || ! write_integer_item + (tuple, FIELD_TRACK_NUMBER, handle, "Track", & length, & items) || + ! write_integer_item (tuple, FIELD_YEAR, handle, "Year", & length, & items)) + goto ERROR; + + for (node = list; node != NULL; node = node->next) + { + gchar * key = ((ValuePair *) node->data)->key; + gchar * value = ((ValuePair *) node->data)->value; + + if (! strcmp (key, "Artist") || ! strcmp (key, "Title") || ! strcmp + (key, "Album") || ! strcmp (key, "Comment") || ! strcmp (key, "Genre") + || ! strcmp (key, "Track") || ! strcmp (key, "Year")) + continue; + + if (! ape_write_item (handle, key, value, & length)) + goto ERROR; + + items ++; } - //skip the tag at the end - add the new tag + + AUDDBG ("Wrote %d items, %d bytes.\n", items, length); + + if (! write_header (length, items, FALSE, handle) || vfs_fseek (handle, + start, SEEK_SET) || ! write_header (length, items, TRUE, handle)) + goto ERROR; + + free_tag_list (list); return TRUE; + +ERROR: + free_tag_list (list); + return FALSE; } + +tag_module_t ape = +{ + .name = "APE", + .type = TAG_TYPE_APE, + .can_handle_file = ape_is_our_file, + .read_tag = ape_read_tag, + .write_tag = ape_write_tag, +}; diff --git a/src/libaudtag/ape/ape.h b/src/libaudtag/ape/ape.h index 2ac0f3a..67f6830 100644 --- a/src/libaudtag/ape/ape.h +++ b/src/libaudtag/ape/ape.h @@ -1,52 +1,30 @@ -#ifndef APE_H - -#define APE_H - -#include <libaudcore/tuple.h> -#include <libaudcore/vfs.h> +/* + * Copyright 2010 John Lindgren + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#ifndef AUDTAG_APE_H +#define AUDTAG_APE_H + +#include "../audtag.h" #include "../tag_module.h" - -enum { - APE_ALBUM = 0, - APE_TITLE, - APE_COPYRIGHT, - APE_ARTIST, - APE_TRACKNR, - APE_YEAR, - APE_GENRE, - APE_COMMENT, - APE_ITEMS_NO -}; - - - -typedef struct apeheader -{ - gchar *preamble; //64 bits - guint32 version; - guint32 tagSize; - guint32 itemCount; - guint32 flags; - guint64 reserved; -}APEv2Header; - -typedef struct tagitem -{ - guint32 size; - guint32 flags; - gchar* key; //null terminated - gchar* value; -}APETagItem; - -gboolean ape_can_handle_file(VFSFile *f); - -Tuple *ape_populate_tuple_from_file(Tuple *tuple,VFSFile *f); - -gboolean ape_write_tuple_to_file(Tuple* tuple, VFSFile *f); +#include "../util.h" extern tag_module_t ape; -mowgli_dictionary_t *tagItems; -mowgli_list_t *tagKeys; -guint32 headerPosition ; #endif diff --git a/src/libaudtag/audtag.c b/src/libaudtag/audtag.c index 3ad1e11..6813798 100644 --- a/src/libaudtag/audtag.c +++ b/src/libaudtag/audtag.c @@ -1,25 +1,67 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + #include "libaudcore/tuple.h" #include "audtag.h" #include "tag_module.h" #include "util.h" -void tag_init(void) { +void tag_init(void) +{ init_tag_modules(); } /* The tuple's file-related attributes are already set */ -Tuple *tag_tuple_read(Tuple *tuple,VFSFile *fd) { - tag_module_t *mod = find_tag_module(fd); - g_return_val_if_fail(mod != NULL, NULL); - AUDDBG("OK\n"); - return mod->populate_tuple_from_file(tuple,fd); +gboolean tag_tuple_read (Tuple * tuple, VFSFile * handle) +{ + tag_module_t * module = find_tag_module (handle, TAG_TYPE_NONE); + + if (module == NULL) + return FALSE; + + return module->read_tag (tuple, handle); +} + +gboolean tag_image_read (VFSFile * handle, void * * data, gint * size) +{ + tag_module_t * module = find_tag_module (handle, TAG_TYPE_NONE); + + if (module == NULL || module->read_image == NULL) + return FALSE; + + return module->read_image (handle, data, size); } -gboolean tag_tuple_write_to_file(Tuple *tuple, VFSFile *fd) { - g_return_val_if_fail((tuple != NULL) && (fd != NULL), FALSE); - tag_module_t *mod = find_tag_module(fd); - g_return_val_if_fail(mod != NULL, -1); +gboolean tag_tuple_write (Tuple * tuple, VFSFile * handle, gint new_type) +{ + tag_module_t * module = find_tag_module (handle, new_type); + + if (module == NULL) + return FALSE; + + return module->write_tag (tuple, handle); +} - return mod->write_tuple_to_file(tuple, fd); +/* deprecated */ +gboolean tag_tuple_write_to_file (Tuple * tuple, VFSFile * handle) +{ + return tag_tuple_write (tuple, handle, TAG_TYPE_NONE); } diff --git a/src/libaudtag/audtag.h b/src/libaudtag/audtag.h index 25089b4..c5338ec 100644 --- a/src/libaudtag/audtag.h +++ b/src/libaudtag/audtag.h @@ -1,3 +1,23 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + /* External Interface of the tagging library */ #ifndef AUDTAG_H @@ -6,18 +26,29 @@ G_BEGIN_DECLS #include <glib.h> -#include <mowgli.h> +#include <mowgli.h> #include "libaudcore/tuple.h" #include "libaudcore/vfs.h" +#include "config.h" + +enum +{ + TAG_TYPE_NONE = 0, + TAG_TYPE_APE, +}; void tag_init(void); void tag_terminate(void); -Tuple *tag_tuple_read(Tuple *tuple, VFSFile *fd); +gboolean tag_tuple_read (Tuple * tuple, VFSFile *fd); +gboolean tag_image_read (VFSFile * handle, void * * data, gint * size); + +/* new_type specifies the type of tag (see the TAG_TYPE_* enum) that should be + * written if the file does not have any existing tag. */ +gboolean tag_tuple_write (Tuple * tuple, VFSFile * handle, gint new_type); -gboolean tag_tuple_write_to_file(Tuple *tuple, VFSFile *fd); +/* deprecated, use tag_tuple_write */ +gboolean tag_tuple_write_to_file (Tuple * tuple, VFSFile * handle); G_END_DECLS #endif /* AUDTAG_H */ - - diff --git a/src/libaudtag/id3/frame.h b/src/libaudtag/id3/frame.h deleted file mode 100644 index 2cf40c7..0000000 --- a/src/libaudtag/id3/frame.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef AUD_ID3_FRAME -#define AUD_ID3_FRAME - -#include <glib-2.0/glib.h> - -enum { - ID3_ALBUM = 0, - ID3_TITLE, - ID3_COMPOSER, - ID3_COPYRIGHT, - ID3_DATE, - ID3_TIME, - ID3_LENGTH, - ID3_ARTIST, - ID3_TRACKNR, - ID3_YEAR, - ID3_GENRE, - ID3_COMMENT, - ID3_TAGS_NO -}; - -char * id3_frames[] = {"TALB","TIT2","TCOM", "TCOP", "TDAT", "TIME", "TLEN", "TPE1", "TRCK", "TYER","TCON", "COMM"}; - -#endif diff --git a/src/libaudtag/id3/id3.c b/src/libaudtag/id3/id3.c deleted file mode 100644 index ed0a131..0000000 --- a/src/libaudtag/id3/id3.c +++ /dev/null @@ -1,541 +0,0 @@ -#include <glib.h> -#include <glib/gstdio.h> - -#include "id3.h" -#include "../util.h" -#include <inttypes.h> -#include "../tag_module.h" -#include "frame.h" - -#define TAG_SIZE 1 - -tag_module_t id3 = {id3_can_handle_file, id3_populate_tuple_from_file, id3_write_tuple_to_file}; -/* reading stuff */ - -gchar *read_iso8859_1(VFSFile *fd, int size) -{ - gchar *value= g_new0(gchar,size); - vfs_fread(value,size,1,fd); - GError *error = NULL; - gsize bytes_read = 0 , bytes_write = 0; - gchar* retVal = g_convert(value,size,"UTF-8","ISO-8859-1",&bytes_read,&bytes_write,&error); - g_free(value); - return retVal; -} - -/* - * Read UTF-16 from the tag and return an uft-8 string for the tuple - */ -gchar* read_unicode(VFSFile *fd, int size) -{ - gchar *value= g_new0(gchar,size); - vfs_fread(value,size,1,fd); - GError *error = NULL; - gsize bytes_read = 0 , bytes_write = 0; - gchar* retVal = g_convert(value,size,"UTF-8","UTF-16",&bytes_read,&bytes_write,&error); - g_free(value); - return retVal; -} - -guint32 read_syncsafe_int32(VFSFile *fd) -{ - guint32 val = read_BEuint32(fd); - guint32 mask = 0x7f; - guint32 intVal = 0; - intVal = ((intVal) | (val & mask)); - int i; - for(i = 0; i<3; i++) - { - mask = mask << 8; - guint32 tmp = (val & mask); - tmp = tmp >> 1; - intVal = intVal | tmp; - }; - return intVal; -} - -ID3v2Header *readHeader(VFSFile *fd) -{ - ID3v2Header *header = g_new0(ID3v2Header,1); - header->id3 = read_char_data(fd,3); - header->version = read_LEuint16(fd); - header->flags = *read_char_data(fd,1); - header->size = read_syncsafe_int32(fd); - return header; -} - -ExtendedHeader *readExtendedHeader(VFSFile *fd) -{ - ExtendedHeader *header = g_new0(ExtendedHeader,1); - header->header_size = read_BEuint32(fd); - header->flags = read_LEuint16(fd); - header->padding_size = read_BEuint32(fd); - return header; -} - -ID3v2FrameHeader *readID3v2FrameHeader(VFSFile *fd) -{ - ID3v2FrameHeader *frameheader = g_new0(ID3v2FrameHeader,1); - frameheader->frame_id = read_char_data(fd,4); - frameheader->size = read_BEuint32(fd); - frameheader->flags = read_LEuint16(fd); - return frameheader; -} - -TextInformationFrame *readTextFrame(VFSFile *fd, TextInformationFrame *frame) -{ - frame->encoding = read_char_data(fd,1)[0]; - - if(frame->encoding == 0) - frame->text = read_iso8859_1(fd,frame->header.size - 1); - - if(frame->encoding == 1) - frame->text = read_unicode(fd,frame->header.size - 1); - return frame; -} - - -gchar* readFrameBody(VFSFile *fd,int size) -{ - if(size == 0) - return NULL; - gchar *b = g_new0(gchar,size); - vfs_fread(b,size,1,fd); - return b; -} - -GenericFrame *readGenericFrame(VFSFile *fd,GenericFrame *gf) -{ - gf->header = readID3v2FrameHeader(fd); - gf->frame_body = readFrameBody(fd,gf->header->size); - - return gf; -} - - -void readAllFrames(VFSFile *fd,int framesSize) -{ - int pos = 0; - int i = 0; - while(pos < framesSize) - { - GenericFrame *gframe = g_new0(GenericFrame,1); - gframe = readGenericFrame(fd,gframe); - if(isValidFrame(gframe)) - { - mowgli_dictionary_add(frames, gframe->header->frame_id, gframe); - mowgli_node_add(gframe->header->frame_id, mowgli_node_create(), frameIDs); - pos += gframe->header->size; - i++; - }else - break; - } - -} - - -/* writing stuff */ -void write_int32(VFSFile *fd, guint32 val) -{ - guint32 be_val = GUINT32_TO_BE(val); - vfs_fwrite(&be_val,4,1,fd); -} - -void write_syncsafe_int32(VFSFile *fd, guint32 val) -{ - //TODO write the corrent function - this is just for testing - int i = 0; - guint32 tmp =0x0; - guint32 mask =0x7f; - guint32 syncVal = 0; - tmp = val & mask; - syncVal = tmp; - for(i = 0;i<3;i++) - { - tmp = 0; - mask <<= 7; - tmp = val & mask; - tmp <<=1; - syncVal |=tmp; - } - guint32 be_val = GUINT32_TO_BE(syncVal); - vfs_fwrite(&be_val,4,1,fd); -} - - -void write_ASCII(VFSFile *fd, int size, gchar* value) -{ - vfs_fwrite(value,size,1,fd); -} - - -void write_utf8(VFSFile *fd, int size,gchar* value) -{ - GError *error = NULL; - gsize bytes_read = 0 , bytes_write = 0; - gchar* isoVal = g_convert(value,size,"ISO-8859-1","UTF-8",&bytes_read,&bytes_write,&error); - vfs_fwrite(isoVal,size,1,fd); -} - -guint32 writeAllFramesToFile(VFSFile *fd) -{ - guint32 size = 0; - mowgli_node_t *n, *tn; - MOWGLI_LIST_FOREACH_SAFE(n, tn, frameIDs->head) - { - GenericFrame *frame = (GenericFrame*)mowgli_dictionary_retrieve(frames,(gchar*)(n->data)); - if(frame) - { - writeGenericFrame(fd,frame); - size += frame->header->size+10; - } - } - return size; -} - -void writeID3HeaderToFile(VFSFile *fd,ID3v2Header *header) -{ - vfs_fwrite(header->id3,3,1,fd); - vfs_fwrite(&header->version,2,1,fd); - vfs_fwrite(&header->flags,1,1,fd); - write_syncsafe_int32(fd,header->size); -} - -void writePaddingToFile(VFSFile *fd, int ksize) -{ - gchar padding = 0; - int i = 0; - for(i=0; i<ksize;i++) - vfs_fwrite(&padding,1,1,fd); -} - - -void writeID3FrameHeaderToFile(VFSFile *fd, ID3v2FrameHeader *header) -{ - vfs_fwrite(header->frame_id,4,1,fd); - write_int32(fd,header->size); - vfs_fwrite(&header->flags,2,1,fd); -} - -void writeGenericFrame(VFSFile *fd,GenericFrame *frame) -{ - writeID3FrameHeaderToFile(fd,frame->header); - vfs_fwrite(frame->frame_body,frame->header->size,1,fd); -} - -gboolean isExtendedHeader(ID3v2Header *header) -{ - if( (header->flags & 0x40) == (0x40)) - return TRUE; - else - return FALSE; -} - -gboolean isUnsynchronisation(ID3v2Header *header) -{ - if((header->flags & 0x80) == 0x80) - return TRUE; - else - return FALSE; -} - -gboolean isExperimental(ID3v2Header *header) -{ - if((header->flags & 0x20) == 0x20) - return TRUE; - else - return FALSE; -} - - -int getFrameID(ID3v2FrameHeader *header) -{ - int i=0; - for(i = 0; i<ID3_TAGS_NO;i++) - { - if(!strcmp(header->frame_id,id3_frames[i])) - return i; - } - return -1; -} - - -void skipFrame(VFSFile *fd, guint32 size) -{ - vfs_fseek(fd,size,SEEK_CUR); -} - -Tuple *assocStrInfo(Tuple *tuple, VFSFile *fd, int field,ID3v2FrameHeader header) -{ - TextInformationFrame *frame = g_new0(TextInformationFrame,1); - frame->header = header; - frame = readTextFrame(fd,frame); -/* AUDDBG("field = %s\n",frame->text);*/ - tuple_associate_string(tuple, field, NULL, frame->text); - return tuple; -} - -Tuple *assocIntInfo(Tuple *tuple, VFSFile *fd, int field,ID3v2FrameHeader header) -{ - TextInformationFrame *frame = g_new0(TextInformationFrame,1); - frame->header = header; - frame = readTextFrame(fd,frame); -/* AUDDBG("field = %s\n",frame->text);*/ - tuple_associate_int(tuple, field, NULL, atoi(frame->text)); - return tuple; -} - -gboolean isValidFrame(GenericFrame *frame) -{ - if(strlen(frame->header->frame_id) != 0) - return TRUE; - else - return FALSE; -} - - - -void add_newISO8859_1FrameFromString(const gchar *value,int id3_field) -{ - GError *error = NULL; - gsize bytes_read = 0 , bytes_write = 0; - gchar* retVal = g_convert(value,strlen(value),"ISO-8859-1","UTF-8",&bytes_read,&bytes_write,&error); - ID3v2FrameHeader *header = g_new0(ID3v2FrameHeader,1); - header->frame_id = id3_frames[id3_field]; - header->flags = 0; - header->size = strlen(retVal)+1; - gchar* buf = g_new0(gchar,header->size+1); - memcpy(buf+1,retVal,header->size); - GenericFrame *frame = g_new0(GenericFrame,1); - frame->header = header; - frame->frame_body = buf; - mowgli_dictionary_add(frames,header->frame_id,frame); - mowgli_node_add(frame->header->frame_id, mowgli_node_create(), frameIDs); - -} - - -void add_newFrameFromTupleStr(Tuple *tuple, int field,int id3_field) -{ - const gchar *value = tuple_get_string(tuple,field,NULL); - add_newISO8859_1FrameFromString(value,id3_field); -} - - -void add_newFrameFromTupleInt(Tuple *tuple,int field,int id3_field) -{ - int intvalue = tuple_get_int(tuple,field,NULL); - gchar *value = g_strdup_printf("%d",intvalue); - add_newISO8859_1FrameFromString(value,id3_field); - -} - - - -void add_frameFromTupleStr(Tuple *tuple, int field,int id3_field) -{ - const gchar *value = tuple_get_string(tuple,field,NULL); - GError *error = NULL; - gsize bytes_read = 0 , bytes_write = 0; - gchar* retVal = g_convert(value,strlen(value),"ISO-8859-1","UTF-8",&bytes_read,&bytes_write,&error); - - GenericFrame *frame = mowgli_dictionary_retrieve(frames,id3_frames[id3_field]); - if(frame != NULL) - { - frame->header->size = strlen(retVal)+1; - gchar* buf = g_new0(gchar,frame->header->size+1); - memcpy(buf+1,retVal,frame->header->size); - frame->frame_body = buf; - } - else - add_newFrameFromTupleStr(tuple,field,id3_field); - -} - -void add_frameFromTupleInt(Tuple *tuple, int field,int id3_field) -{ - int intvalue = tuple_get_int(tuple,field,NULL); - gchar *value = g_strdup_printf("%d",intvalue); - GError *error = NULL; - gsize bytes_read = 0 , bytes_write = 0; - gchar* retVal = g_convert(value,strlen(value),"ISO-8859-1","UTF-8",&bytes_read,&bytes_write,&error); - - GenericFrame *frame = mowgli_dictionary_retrieve(frames,id3_frames[id3_field]); - if(frame != NULL) - { - frame->header->size = strlen(retVal)+1; - gchar* buf = g_new0(gchar,frame->header->size+1); - memcpy(buf+1,retVal,frame->header->size); - frame->frame_body = buf; - } - else - add_newFrameFromTupleStr(tuple,field,id3_field); - -} - -gboolean id3_can_handle_file(VFSFile *f) -{ - ID3v2Header *header = readHeader(f); - if(!strcmp(header->id3,"ID3")) - return TRUE; - return FALSE; -} - - - -Tuple *id3_populate_tuple_from_file(Tuple *tuple, VFSFile *f) -{ - //reset file position - vfs_fseek(f,0,SEEK_SET); -// Tuple *tuple = tuple_new_from_filename(f->uri); - ExtendedHeader *extHeader; - ID3v2Header *header = readHeader(f); - int pos = 0; - if(isExtendedHeader(header)) - extHeader = readExtendedHeader(f); - - while(pos < header->size) - { - ID3v2FrameHeader *header = readID3v2FrameHeader(f); - int id = getFrameID(header); - pos = pos + header->size + 10; - switch(id) - { - case ID3_ALBUM: - { - tuple = assocStrInfo(tuple,f,FIELD_ALBUM,*header); - }break; - case ID3_TITLE: - { - tuple = assocStrInfo(tuple,f,FIELD_TITLE,*header); - }break; - case ID3_COMPOSER: - { - // tuple = assocInfo(tuple,f,FIELD_ARTIST,*header); - }break; - case ID3_COPYRIGHT: - { - tuple = assocStrInfo(tuple,f,FIELD_COPYRIGHT,*header); - }break; - case ID3_DATE: - { - tuple = assocStrInfo(tuple,f,FIELD_DATE,*header); - }break; - case ID3_TIME: - { - // tuple = assocIntInfo(tuple,f,FIELD_LENGTH,*header); - }break; - case ID3_LENGTH: - { - tuple = assocIntInfo(tuple,f,FIELD_LENGTH,*header); - }break; - case ID3_ARTIST: - { - tuple = assocStrInfo(tuple,f,FIELD_ARTIST,*header); - }break; - case ID3_TRACKNR: - { - tuple = assocIntInfo(tuple,f,FIELD_TRACK_NUMBER,*header); - }break; - case ID3_YEAR: - { - tuple = assocIntInfo(tuple,f,FIELD_YEAR,*header); - }break; - case ID3_GENRE: - { - tuple = assocStrInfo(tuple,f,FIELD_GENRE,*header); - }break; - case ID3_COMMENT: - { - tuple = assocStrInfo(tuple,f,FIELD_COMMENT,*header); - }break; - default: - { - //we a a frame that I dont need so skip it - skipFrame(f,header->size); - } - } - } - return tuple; -} - - -gboolean id3_write_tuple_to_file(Tuple* tuple, VFSFile *f) -{ - VFSFile *tmp; - vfs_fseek(f,0,SEEK_SET); - - ExtendedHeader *extHeader; - if(frameIDs != NULL) - { - mowgli_node_t *n, *tn; - MOWGLI_LIST_FOREACH_SAFE(n, tn, frameIDs->head) - { - mowgli_node_delete(n,frameIDs); - } - } - frameIDs = mowgli_list_create(); - ID3v2Header *header = readHeader(f); - int framesSize = header->size; - - if(isExtendedHeader(header)) - { - extHeader = readExtendedHeader(f); - framesSize -= 10; - framesSize -= extHeader->padding_size; - } - - //read all frames into generic frames; - frames = mowgli_dictionary_create(strcasecmp); - readAllFrames(f,header->size); - - //make the new frames from tuple and replace in the dictinonary the old frames with the new ones - if(tuple_get_string(tuple, FIELD_ARTIST, NULL)) - add_frameFromTupleStr(tuple, FIELD_ARTIST,ID3_ARTIST); - - - if(tuple_get_string(tuple, FIELD_TITLE, NULL)) - add_frameFromTupleStr(tuple, FIELD_TITLE,ID3_TITLE); - - - if(tuple_get_string(tuple, FIELD_ALBUM, NULL)) - add_frameFromTupleStr(tuple, FIELD_ALBUM,ID3_ALBUM); - - if(tuple_get_string(tuple,FIELD_COMMENT,NULL)) - add_frameFromTupleStr(tuple,FIELD_COMMENT,ID3_COMMENT); - - if(tuple_get_string(tuple,FIELD_GENRE,NULL)) - add_frameFromTupleStr(tuple,FIELD_GENRE,ID3_GENRE); - - if(tuple_get_int(tuple,FIELD_YEAR,NULL) !=0 ) - add_frameFromTupleInt(tuple,FIELD_YEAR,ID3_YEAR); - - if(tuple_get_int(tuple,FIELD_TRACK_NUMBER,NULL) != 0) - add_frameFromTupleInt(tuple,FIELD_TRACK_NUMBER,ID3_TRACKNR); - - const gchar *tmpdir = g_get_tmp_dir(); - gchar *tmp_path = g_strdup_printf("file://%s/%s", tmpdir, "tmp.mpc"); - tmp = vfs_fopen(tmp_path, "w+"); - - int oldSize = header->size; - header->size = TAG_SIZE*1024; - - writeID3HeaderToFile(tmp,header); - - int size = writeAllFramesToFile(tmp); - writePaddingToFile(tmp,TAG_SIZE*1024-size-10); - - copyAudioToFile(f,tmp,oldSize); - - - gchar *uri = g_strdup(f -> uri); - vfs_fclose(tmp); - gchar* f1 = g_filename_from_uri(tmp_path,NULL,NULL); - gchar* f2 = g_filename_from_uri(uri,NULL,NULL); - if (g_rename(f1,f2 ) == 0) { - AUDDBG("the tag was updated successfully\n"); - } else { - AUDDBG("an error has occured\n"); - } - return TRUE; -} diff --git a/src/libaudtag/id3/id3.h b/src/libaudtag/id3/id3.h deleted file mode 100644 index b8a0cca..0000000 --- a/src/libaudtag/id3/id3.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef ID3_H - -#define ID3_H - -#include <libaudcore/tuple.h> -#include <libaudcore/vfs.h> -#include "../tag_module.h" - - -typedef struct id3v2 -{ - gchar *id3; - guint16 version; - gchar flags; - guint32 size; -} ID3v2Header; - -typedef struct extHeader -{ - guint32 header_size; - guint16 flags; - guint32 padding_size; -}ExtendedHeader; - -typedef struct frameheader -{ - gchar* frame_id; - guint32 size; - guint16 flags; -}ID3v2FrameHeader; - -typedef struct genericframe -{ - ID3v2FrameHeader *header; - gchar* frame_body; -}GenericFrame; - -typedef struct textframe -{ - ID3v2FrameHeader header; - gchar encoding; - gchar* text; -}TextInformationFrame; - -gchar *read_iso8859_1(VFSFile *fd, int size); - -gchar* read_unicode(VFSFile *fd, int size); - -guint32 read_syncsafe_int32(VFSFile *fd); - -ID3v2Header *readHeader(VFSFile *fd); - -ExtendedHeader *readExtendedHeader(VFSFile *fd); - -ID3v2FrameHeader *readID3v2FrameHeader(VFSFile *fd); - -TextInformationFrame *readTextFrame(VFSFile *fd, TextInformationFrame *frame); - -gchar* readFrameBody(VFSFile *fd,int size); - -GenericFrame *readGenericFrame(VFSFile *fd,GenericFrame *gf); - -void readAllFrames(VFSFile *fd,int framesSize); - -void write_int32(VFSFile *fd, guint32 val); - -void write_syncsafe_int32(VFSFile *fd, guint32 val); - -void write_ASCII(VFSFile *fd, int size, gchar* value); - -void write_utf8(VFSFile *fd, int size,gchar* value); - -guint32 writeAllFramesToFile(VFSFile *fd); - -void writeID3HeaderToFile(VFSFile *fd,ID3v2Header *header); - -void writePaddingToFile(VFSFile *fd, int ksize); - -void writeID3FrameHeaderToFile(VFSFile *fd, ID3v2FrameHeader *header); - -void writeGenericFrame(VFSFile *fd,GenericFrame *frame); - -gboolean isExtendedHeader(ID3v2Header *header); - -gboolean isUnsynchronisation(ID3v2Header *header); - -gboolean isExperimental(ID3v2Header *header); - -int getFrameID(ID3v2FrameHeader *header); - -void skipFrame(VFSFile *fd, guint32 size); - -Tuple *assocStrInfo(Tuple *tuple, VFSFile *fd, int field,ID3v2FrameHeader header); - -Tuple *assocIntInfo(Tuple *tuple, VFSFile *fd, int field,ID3v2FrameHeader header); - -gboolean isValidFrame(GenericFrame *frame); - -void add_newISO8859_1FrameFromString(const gchar *value,int id3_field); - -void add_newFrameFromTupleStr(Tuple *tuple, int field,int id3_field); - -void add_newFrameFromTupleInt(Tuple *tuple,int field,int id3_field); - -void add_frameFromTupleStr(Tuple *tuple, int field,int id3_field); - -void add_frameFromTupleInt(Tuple *tuple, int field,int id3_field); - -gboolean id3_can_handle_file(VFSFile *f); - -Tuple *id3_populate_tuple_from_file(Tuple *tuple,VFSFile *f); - -gboolean id3_write_tuple_to_file(Tuple* tuple, VFSFile *f); - -extern tag_module_t id3; -mowgli_dictionary_t *frames ; -mowgli_list_t *frameIDs; -#endif diff --git a/src/libaudtag/id3/id3v1.c b/src/libaudtag/id3/id3v1.c new file mode 100644 index 0000000..9b593a1 --- /dev/null +++ b/src/libaudtag/id3/id3v1.c @@ -0,0 +1,145 @@ +/* + * Copyright 2010 Tony Vroon + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#include <glib.h> +#include <glib/gstdio.h> + +#include "id3v1.h" +#include "../util.h" +#include <inttypes.h> +#include "../tag_module.h" + +static gboolean has_id3v1_ext; + +gboolean id3v1_can_handle_file(VFSFile *f) +{ + gchar *tag = g_new0(gchar, 4); + + if (vfs_fseek(f, -355, SEEK_END)) + return FALSE; + tag = read_char_data(f, 4); + if (!strncmp(tag, "TAG+", 4)) + has_id3v1_ext = TRUE; + else + has_id3v1_ext = FALSE; + + if (vfs_fseek(f, -128, SEEK_END)) + return FALSE; + tag = read_char_data(f, 3); + if (!strncmp(tag, "TAG", 3)) + { + g_free(tag); + return TRUE; + } + + g_free(tag); + return FALSE; +} + +static gchar *convert_to_utf8(gchar *str) +{ + return g_strchomp(str_to_utf8(str)); +} + +gboolean id3v1_read_tag (Tuple * tuple, VFSFile * f) +{ + gchar *title = g_new0(gchar, 30); + gchar *artist = g_new0(gchar, 30); + gchar *album = g_new0(gchar, 30); + gchar *year = g_new0(gchar, 4); + gchar *comment = g_new0(gchar, 30); + gchar *track = g_new0(gchar, 1); + gchar *genre = g_new0(gchar, 1); + gboolean genre_set = FALSE; + if (vfs_fseek(f, -125, SEEK_END)) + return FALSE; + title = read_char_data(f, 30); + artist = read_char_data(f, 30); + album = read_char_data(f, 30); + year = read_char_data(f, 4); + comment = read_char_data(f, 30); + genre = read_char_data(f, 1); + + if (comment[28] == 0 && comment[29] != 0) + { + *track = comment[29]; + } + + title = convert_to_utf8(title); + artist = convert_to_utf8(artist); + album = convert_to_utf8(album); + comment = convert_to_utf8(comment); + + if (has_id3v1_ext) + { + vfs_fseek(f, -351, SEEK_END); + gchar *tmp_title = g_strconcat(title, convert_to_utf8(read_char_data(f, 60)), NULL); + gchar *tmp_artist = g_strconcat(artist, convert_to_utf8(read_char_data(f, 60)), NULL); + gchar *tmp_album = g_strconcat(album, convert_to_utf8(read_char_data(f, 60)), NULL); + vfs_fseek(f, -170, SEEK_END); + gchar *tmp_genre = g_new0(gchar, 30); + tmp_genre = convert_to_utf8(read_char_data(f, 30)); + g_free(title); + g_free(artist); + g_free(album); + title = tmp_title; + artist = tmp_artist; + album = tmp_album; + + if (g_strcmp0(tmp_genre, NULL) == 1) + { + tuple_associate_string(tuple, FIELD_GENRE, NULL, tmp_genre); + genre_set = TRUE; + } + + g_free(tmp_genre); + } + + tuple_associate_string(tuple, FIELD_TITLE, NULL, title); + tuple_associate_string(tuple, FIELD_ARTIST, NULL, artist); + tuple_associate_string(tuple, FIELD_ALBUM, NULL, album); + tuple_associate_int(tuple, FIELD_YEAR, NULL, atoi(year)); + tuple_associate_string(tuple, FIELD_COMMENT, NULL, comment); + tuple_associate_int(tuple, FIELD_TRACK_NUMBER, NULL, *track); + if (!genre_set) tuple_associate_string(tuple, FIELD_GENRE, NULL, convert_numericgenre_to_text(*genre)); + + g_free(title); + g_free(artist); + g_free(album); + g_free(year); + g_free(comment); + g_free(track); + g_free(genre); + + return TRUE; +} + +gboolean id3v1_write_tag (Tuple * tuple, VFSFile * handle) +{ + return FALSE; +} + +tag_module_t id3v1 = { + .name = "ID3v1", + .can_handle_file = id3v1_can_handle_file, + .read_tag = id3v1_read_tag, + .write_tag = id3v1_write_tag, +}; + diff --git a/src/libaudtag/id3/id3v1.h b/src/libaudtag/id3/id3v1.h new file mode 100644 index 0000000..77ebee9 --- /dev/null +++ b/src/libaudtag/id3/id3v1.h @@ -0,0 +1,36 @@ +/* + * Copyright 2010 Tony Vroon + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#ifndef ID3V1_H + +#define ID3V1_H + +#include <libaudcore/audstrings.h> +#include <libaudcore/tuple.h> +#include <libaudcore/vfs.h> +#include "../tag_module.h" + +/* TAG plugin API */ +gboolean id3v1_can_handle_file(VFSFile *f); +gboolean id3v1_read_tag (Tuple * tuple, VFSFile * handle); +gboolean id3v1_write_tag (Tuple * tuple, VFSFile * handle); + +extern tag_module_t id3v1; +#endif diff --git a/src/libaudtag/id3/id3v22.c b/src/libaudtag/id3/id3v22.c new file mode 100644 index 0000000..4699bf7 --- /dev/null +++ b/src/libaudtag/id3/id3v22.c @@ -0,0 +1,890 @@ +/* + * Copyright 2009 Paula Stanciu + * Copyright 2010 John Lindgren + * Copyright 2010 Tony Vroon + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#include <glib.h> + +#include <libaudcore/audstrings.h> + +#include "id3v22.h" +#include "../util.h" + +enum +{ + ID3_ALBUM = 0, + ID3_TITLE, + ID3_COMPOSER, + ID3_COPYRIGHT, + ID3_DATE, + ID3_TIME, + ID3_LENGTH, + ID3_ARTIST, + ID3_TRACKNR, + ID3_YEAR, + ID3_GENRE, + ID3_COMMENT, + ID3_ENCODER, + ID3_TXX, + ID3_RVA, + ID3_TAGS_NO +}; + +static const gchar * id3_frames[ID3_TAGS_NO] = {"TAL", "TT2", "TCM", "TCR", +"TDA", "TIM", "TLE", "TPE", "TRK", "TYE", "TCO", "COM", "TSS", "TXX", "RVA"}; + +#pragma pack(push) /* must be byte-aligned */ +#pragma pack(1) +typedef struct +{ + gchar magic[3]; + guchar version; + guchar revision; + guchar flags; + guint32 size; +} +ID3v2Header; + +typedef struct +{ + gchar key[3]; + guint32 size; +} +ID3v2FrameHeader; +#pragma pack(pop) + +typedef struct +{ + gchar key[5]; + guchar * data; + gint size; +} +GenericFrame; + +#define ID3_HEADER_SYNCSAFE 0x40 +#define ID3_HEADER_COMPRESSED 0x20 + +#define TAG_SIZE 1 + +static mowgli_dictionary_t * frames = NULL; +static mowgli_list_t * frameIDs = NULL; + +#define write_syncsafe_int32(x) vfs_fput_be32 (syncsafe32 (x)) + +static gboolean validate_header (ID3v2Header * header, gboolean is_footer) +{ + if (memcmp (header->magic, is_footer ? "3DI" : "ID3", 3)) + return FALSE; + + if ((header->version != 2) || header->revision != 0) + return FALSE; + + header->size = unsyncsafe32 (GUINT32_FROM_BE (header->size)); + + AUDDBG ("Found ID3v2 %s:\n", is_footer ? "footer" : "header"); + AUDDBG (" magic = %.3s\n", header->magic); + AUDDBG (" version = %d\n", (gint) header->version); + AUDDBG (" revision = %d\n", (gint) header->revision); + AUDDBG (" flags = %x\n", (gint) header->flags); + AUDDBG (" size = %d\n", (gint) header->size); + return TRUE; +} + +static gboolean read_header (VFSFile * handle, gint * version, gboolean * + syncsafe, gsize * offset, gint * header_size, gint * data_size, gint * + footer_size) +{ + ID3v2Header header, footer; + + if (vfs_fseek (handle, 0, SEEK_SET)) + return FALSE; + + if (vfs_fread (& header, 1, sizeof (ID3v2Header), handle) != sizeof + (ID3v2Header)) + return FALSE; + + if (validate_header (& header, FALSE)) + { + * offset = 0; + * version = header.version; + * header_size = sizeof (ID3v2Header); + * data_size = header.size; + } + else + { + gsize end = vfs_fsize (handle); + + if (end < 0) + return FALSE; + + if (vfs_fseek (handle, end - sizeof (ID3v2Header), SEEK_SET)) + return FALSE; + + if (vfs_fread (& footer, 1, sizeof (ID3v2Header), handle) != sizeof + (ID3v2Header)) + return FALSE; + + if (! validate_header (& footer, TRUE)) + return FALSE; + + * offset = end - 2 * sizeof (ID3v2Header) - footer.size; + * version = footer.version; + * header_size = sizeof (ID3v2Header); + * data_size = footer.size; + * footer_size = sizeof (ID3v2Header); + + if (vfs_fseek (handle, * offset, SEEK_SET)) + return FALSE; + + if (vfs_fread (& header, 1, sizeof (ID3v2Header), handle) != sizeof + (ID3v2Header)) + return FALSE; + + if (! validate_header (& header, FALSE)) + return FALSE; + } + + * syncsafe = (header.flags & ID3_HEADER_SYNCSAFE) ? TRUE : FALSE; + + AUDDBG ("Offset = %d, header size = %d, data size = %d, footer size = " + "%d.\n", (gint) * offset, * header_size, * data_size, * footer_size); + + return TRUE; +} + +static gint unsyncsafe (guchar * data, gint size) +{ + guchar * get = data, * set = data; + + while (size --) + { + guchar c = * set ++ = * get ++; + + if (c == 0xff && size && ! get[0]) + { + size --; + get ++; + } + } + + return set - data; +} + +static gboolean read_frame (VFSFile * handle, gint max_size, gint version, + gboolean syncsafe, gint * frame_size, gchar * key, guchar * * data, gint * size) +{ + ID3v2FrameHeader header; + gint skip = 0; + + if ((max_size -= sizeof (ID3v2FrameHeader)) < 0) + return FALSE; + + if (vfs_fread (& header, 1, sizeof (ID3v2FrameHeader), handle) != sizeof + (ID3v2FrameHeader)) + return FALSE; + + if (! header.key[0]) /* padding */ + return FALSE; + + header.size = (version == 3) ? GUINT32_FROM_BE (header.size) : unsyncsafe32 + (GUINT32_FROM_BE (header.size)); + header.flags = GUINT16_FROM_BE (header.flags); + + if (header.size > max_size) + return FALSE; + + AUDDBG ("Found frame:\n"); + AUDDBG (" key = %.4s\n", header.key); + AUDDBG (" size = %d\n", (gint) header.size); + AUDDBG (" flags = %x\n", (gint) header.flags); + + * frame_size = sizeof (ID3v2FrameHeader) + header.size; + sprintf (key, "%.4s", header.key); + + if (header.flags & (ID3_FRAME_COMPRESSED | ID3_FRAME_ENCRYPTED)) + { + AUDDBG ("Hit compressed/encrypted frame %s.\n", key); + return FALSE; + } + + if (header.flags & ID3_FRAME_HAS_GROUP) + skip ++; + if (header.flags & ID3_FRAME_HAS_LENGTH) + skip += 4; + + if (skip > 0 && vfs_fseek (handle, skip, SEEK_CUR)) + return FALSE; + + * size = header.size - skip; + * data = g_malloc (* size); + + if (vfs_fread (* data, 1, * size, handle) != * size) + return FALSE; + + if (syncsafe || (header.flags & ID3_FRAME_SYNCSAFE)) + * size = unsyncsafe (* data, * size); + + AUDDBG ("Data size = %d.\n", * size); + return TRUE; +} + +static gchar * convert_text (const gchar * text, gint length, gint encoding, + gboolean nulled, gint * _converted, const gchar * * after) +{ + gchar * buffer = NULL; + gsize converted = 0; + + if (nulled) + { + const guchar null16[] = {0, 0}; + const gchar * null; + + switch (encoding) + { + case 0: + case 3: + if ((null = memchr (text, 0, length)) == NULL) + return NULL; + + length = null - text; + + if (after != NULL) + * after = null + 1; + + break; + case 1: + case 2: + if ((null = memfind (text, length, null16, 2)) == NULL) + return NULL; + + length = null - text; + + if (after != NULL) + * after = null + 2; + + break; + } + } + + switch (encoding) + { + case 0: + buffer = g_convert (text, length, "UTF-8", "ISO-8859-1", NULL, + & converted, NULL); + break; + case 1: + if (text[0] == (gchar) 0xff) + buffer = g_convert (text + 2, length - 2, "UTF-8", "UTF-16LE", NULL, + & converted, NULL); + else + buffer = g_convert (text + 2, length - 2, "UTF-8", "UTF-16BE", NULL, + & converted, NULL); + + break; + case 2: + buffer = g_convert (text, length, "UTF-8", "UTF-16BE", NULL, + & converted, NULL); + break; + case 3: + buffer = g_malloc (length + 1); + memcpy (buffer, text, length); + buffer[length] = 0; + converted = length; + break; + } + + if (_converted != NULL) + * _converted = converted; + + return buffer; +} + +static gchar * decode_text_frame (const guchar * data, gint size) +{ + return convert_text ((const gchar *) data + 1, size - 1, data[0], FALSE, + NULL, NULL); +} + +static gboolean decode_comment_frame (const guchar * _data, gint size, gchar * * + lang, gchar * * type, gchar * * value) +{ + const gchar * data = (const gchar *) _data; + gchar * pair, * sep; + gint converted; + + pair = convert_text (data + 4, size - 4, data[0], FALSE, & converted, NULL); + + if (pair == NULL || (sep = memchr (pair, 0, converted)) == NULL) + return FALSE; + + * lang = g_strndup (data + 1, 3); + * type = g_strdup (pair); + * value = g_strdup (sep + 1); + + g_free (pair); + return TRUE; +} + +static void free_generic_frame (GenericFrame * frame) +{ + g_free (frame->data); + g_free (frame); +} + +static void read_all_frames (VFSFile * handle, gint version, gboolean syncsafe, + gint data_size) +{ + gint pos; + + for (pos = 0; pos < data_size; ) + { + gint frame_size, size; + gchar key[5]; + guchar * data; + GenericFrame * frame; + + if (! read_frame (handle, data_size - pos, version, syncsafe, + & frame_size, key, & data, & size)) + break; + + frame = g_malloc (sizeof (GenericFrame)); + strcpy (frame->key, key); + frame->data = data; + frame->size = size; + + mowgli_dictionary_add (frames, frame->key, frame); + mowgli_node_add (frame->key, mowgli_node_create (), frameIDs); + + pos += frame_size; + } +} + +static gboolean write_frame (VFSFile * handle, GenericFrame * frame, gint * + frame_size) +{ + ID3v2FrameHeader header; + + memcpy (header.key, frame->key, 4); + header.size = syncsafe32 (frame->size); + header.size = GUINT32_TO_BE (header.size); + header.flags = 0; + + if (vfs_fwrite (& header, 1, sizeof (ID3v2FrameHeader), handle) != sizeof + (ID3v2FrameHeader)) + return FALSE; + + if (vfs_fwrite (frame->data, 1, frame->size, handle) != frame->size) + return FALSE; + + * frame_size = sizeof (ID3v2FrameHeader) + frame->size; + return TRUE; +} + +static guint32 writeAllFramesToFile (VFSFile * fd) +{ + guint32 size = 0; + mowgli_node_t *n, *tn; + MOWGLI_LIST_FOREACH_SAFE(n, tn, frameIDs->head) + { + GenericFrame *frame = (GenericFrame *) mowgli_dictionary_retrieve(frames, (gchar *) (n->data)); + if (frame) + { + gint frame_size; + + if (! write_frame (fd, frame, & frame_size)) + break; + + size += frame_size; + } + } + return size; +} + +static gboolean write_header (VFSFile * handle, gint size, gboolean is_footer) +{ + ID3v2Header header; + + memcpy (header.magic, is_footer ? "3DI" : "ID3", 3); + header.version = 4; + header.revision = 0; + header.flags = ID3_HEADER_HAS_FOOTER; + header.size = syncsafe32 (size); + header.size = GUINT32_TO_BE (header.size); + + return vfs_fwrite (& header, 1, sizeof (ID3v2Header), handle) == sizeof + (ID3v2Header); +} + +static gint get_frame_id (const gchar * key) +{ + gint id; + + for (id = 0; id < ID3_TAGS_NO; id ++) + { + if (! strcmp (key, id3_frames[id])) + return id; + } + + return -1; +} + +static void associate_string (Tuple * tuple, gint field, const gchar * + customfield, const guchar * data, gint size) +{ + gchar * text = decode_text_frame (data, size); + + if (text == NULL) + return; + + if (customfield != NULL) + AUDDBG ("Custom field %s = %s.\n", customfield, text); + else + AUDDBG ("Field %i = %s.\n", field, text); + + tuple_associate_string (tuple, field, customfield, text); + g_free (text); +} + +static void associate_int (Tuple * tuple, gint field, const gchar * + customfield, const guchar * data, gint size) +{ + gchar * text = decode_text_frame (data, size); + + if (text == NULL) + return; + + if (customfield != NULL) + AUDDBG ("Custom field %s = %s.\n", customfield, text); + else + AUDDBG ("Field %i = %s.\n", field, text); + + tuple_associate_int (tuple, field, customfield, atoi (text)); + g_free (text); +} + +static void decode_comment (Tuple * tuple, const guchar * data, gint size) +{ + gchar * lang, * type, * value; + + if (! decode_comment_frame (data, size, & lang, & type, & value)) + return; + + AUDDBG ("Comment: lang = %s, type = %s, value = %s.\n", lang, type, value); + + if (! type[0]) /* blank type == actual comment */ + tuple_associate_string (tuple, FIELD_COMMENT, NULL, value); + + g_free (lang); + g_free (type); + g_free (value); +} + +static void decode_txx (Tuple * tuple, const guchar * data, gint size) +{ + gchar * text = decode_text_frame (data, size); + + if (text == NULL) + return; + + gchar *separator = strchr(text, 0); + + if (separator == NULL) + return; + + gchar * value = separator + 1; + AUDDBG ("TXX: %s = %s.\n", text, value); + tuple_associate_string (tuple, -1, text, value); + + g_free (text); +} + +static gboolean decode_rva_block (const guchar * * _data, gint * _size, gint * + channel, gint * adjustment, gint * adjustment_unit, gint * peak, gint * + peak_unit) +{ + const guchar * data = * _data; + gint size = * _size; + gint peak_bits; + + if (size < 4) + return FALSE; + + * channel = data[0]; + * adjustment = (gchar) data[1]; /* first byte is signed */ + * adjustment = (* adjustment << 8) | data[2]; + * adjustment_unit = 512; + peak_bits = data[3]; + + data += 4; + size -= 4; + + AUDDBG ("RVA block: channel = %d, adjustment = %d/%d, peak bits = %d\n", + * channel, * adjustment, * adjustment_unit, peak_bits); + + if (peak_bits > 0 && peak_bits < sizeof (gint) * 8) + { + gint bytes = (peak_bits + 7) / 8; + gint count; + + if (bytes > size) + return FALSE; + + * peak = 0; + * peak_unit = 1 << peak_bits; + + for (count = 0; count < bytes; count ++) + * peak = (* peak << 8) | data[count]; + + data += bytes; + size -= count; + + AUDDBG ("RVA block: peak = %d/%d\n", * peak, * peak_unit); + } + else + { + * peak = 0; + * peak_unit = 0; + } + + * _data = data; + * _size = size; + return TRUE; +} + +static void decode_rva (Tuple * tuple, const guchar * data, gint size) +{ + const gchar * domain; + gint channel, adjustment, adjustment_unit, peak, peak_unit; + + if (memchr (data, 0, size) == NULL) + return; + + domain = (const gchar *) data; + + AUDDBG ("RVA domain: %s\n", domain); + + size -= strlen (domain) + 1; + data += strlen (domain) + 1; + + while (size > 0) + { + if (! decode_rva_block (& data, & size, & channel, & adjustment, + & adjustment_unit, & peak, & peak_unit)) + break; + + if (channel != 1) /* specific channel? */ + continue; + + if (tuple_get_value_type (tuple, FIELD_GAIN_GAIN_UNIT, NULL) == + TUPLE_INT) + adjustment = adjustment * (gint64) tuple_get_int (tuple, + FIELD_GAIN_GAIN_UNIT, NULL) / adjustment_unit; + else + tuple_associate_int (tuple, FIELD_GAIN_GAIN_UNIT, NULL, + adjustment_unit); + + if (peak_unit) + { + if (tuple_get_value_type (tuple, FIELD_GAIN_PEAK_UNIT, NULL) == + TUPLE_INT) + peak = peak * (gint64) tuple_get_int (tuple, + FIELD_GAIN_PEAK_UNIT, NULL) / peak_unit; + else + tuple_associate_int (tuple, FIELD_GAIN_PEAK_UNIT, NULL, + peak_unit); + } + + if (! strcasecmp (domain, "album")) + { + tuple_associate_int (tuple, FIELD_GAIN_ALBUM_GAIN, NULL, adjustment); + + if (peak_unit) + tuple_associate_int (tuple, FIELD_GAIN_ALBUM_PEAK, NULL, peak); + } + else if (! strcasecmp (domain, "track")) + { + tuple_associate_int (tuple, FIELD_GAIN_TRACK_GAIN, NULL, adjustment); + + if (peak_unit) + tuple_associate_int (tuple, FIELD_GAIN_TRACK_PEAK, NULL, peak); + } + } +} + +static void decode_genre (Tuple * tuple, const guchar * data, gint size) +{ + gint numericgenre; + gchar * text = decode_text_frame (data, size); + + if (text == NULL) + return; + + if (text[0] == '(') + numericgenre = atoi (text + 1); + else + numericgenre = atoi (text); + + if (numericgenre > 0) + { + tuple_associate_string(tuple, FIELD_GENRE, NULL, convert_numericgenre_to_text(numericgenre)); + return; + } + tuple_associate_string(tuple, FIELD_GENRE, NULL, text); + g_free (text); + return; +} + +static GenericFrame * add_generic_frame (gint id, gint size) +{ + GenericFrame * frame = mowgli_dictionary_retrieve (frames, id3_frames[id]); + + if (frame == NULL) + { + frame = g_malloc (sizeof (GenericFrame)); + strcpy (frame->key, id3_frames[id]); + mowgli_dictionary_add (frames, frame->key, frame); + mowgli_node_add (frame->key, mowgli_node_create (), frameIDs); + } + else + g_free (frame->data); + + frame->data = g_malloc (size); + frame->size = size; + return frame; +} + +static void add_text_frame (gint id, const gchar * text) +{ + gint length = strlen (text); + GenericFrame * frame = add_generic_frame (id, length + 1); + + frame->data[0] = 3; /* UTF-8 encoding */ + memcpy (frame->data + 1, text, length); +} + +static void add_comment_frame (const gchar * text) +{ + gint length = strlen (text); + GenericFrame * frame = add_generic_frame (ID3_COMMENT, length + 5); + + frame->data[0] = 3; /* UTF-8 encoding */ + strcpy ((gchar *) frame->data + 1, "eng"); /* well, it *might* be English */ + memcpy (frame->data + 5, text, length); +} + +static void add_frameFromTupleStr (Tuple * tuple, int field, int id3_field) +{ + add_text_frame (id3_field, tuple_get_string (tuple, field, NULL)); +} + +static void add_frameFromTupleInt (Tuple * tuple, int field, int id3_field) +{ + gchar scratch[16]; + + snprintf (scratch, sizeof scratch, "%d", tuple_get_int (tuple, field, NULL)); + add_text_frame (id3_field, scratch); +} + +static gboolean id3v22_can_handle_file (VFSFile * handle) +{ + gint version, header_size, data_size, footer_size; + gboolean syncsafe; + gsize offset; + + return read_header (handle, & version, & syncsafe, & offset, & header_size, + & data_size, & footer_size); +} + +static gboolean id3v22_read_tag (Tuple * tuple, VFSFile * handle) +{ + gint version, header_size, data_size, footer_size; + gboolean syncsafe; + gsize offset; + gint pos; + + if (! read_header (handle, & version, & syncsafe, & offset, & header_size, + & data_size, & footer_size)) + return FALSE; + + for (pos = 0; pos < data_size; ) + { + gint frame_size, size, id; + gchar key[5]; + guchar * data; + + if (! read_frame (handle, data_size - pos, version, syncsafe, + & frame_size, key, & data, & size)) + break; + + id = get_frame_id (key); + + switch (id) + { + case ID3_ALBUM: + associate_string (tuple, FIELD_ALBUM, NULL, data, size); + break; + case ID3_TITLE: + associate_string (tuple, FIELD_TITLE, NULL, data, size); + break; + case ID3_COMPOSER: + associate_string (tuple, FIELD_COMPOSER, NULL, data, size); + break; + case ID3_COPYRIGHT: + associate_string (tuple, FIELD_COPYRIGHT, NULL, data, size); + break; + case ID3_DATE: + associate_string (tuple, FIELD_DATE, NULL, data, size); + break; + case ID3_TIME: + associate_int (tuple, FIELD_LENGTH, NULL, data, size); + break; + case ID3_LENGTH: + associate_int (tuple, FIELD_LENGTH, NULL, data, size); + break; + case ID3_ARTIST: + associate_string (tuple, FIELD_ARTIST, NULL, data, size); + break; + case ID3_TRACKNR: + associate_int (tuple, FIELD_TRACK_NUMBER, NULL, data, size); + break; + case ID3_YEAR: + associate_int (tuple, FIELD_YEAR, NULL, data, size); + break; + case ID3_GENRE: + decode_genre (tuple, data, size); + break; + case ID3_COMMENT: + decode_comment (tuple, data, size); + break; + case ID3_ENCODER: + associate_string (tuple, -1, "encoder", data, size); + break; + case ID3_TXX: + decode_txx (tuple, data, size); + break; + case ID3_RVA: + decode_rva (tuple, data, size); + break; + default: + AUDDBG ("Ignoring unsupported ID3 frame %s.\n", key); + break; + } + + g_free (data); + pos += frame_size; + } + + return TRUE; +} + +static gboolean parse_pic (const guchar * data, gint size, gchar * * mime, + gint * type, gchar * * desc, void * * image_data, gint * image_size) +{ + const guchar * sep; + const guchar * after; + + if (size < 2 || (sep = memchr (data + 1, 0, size - 2)) == NULL) + return FALSE; + + if ((* desc = convert_text ((const gchar *) sep + 2, data + size - sep - 2, + data[0], TRUE, NULL, (const gchar * *) & after)) == NULL) + return FALSE; + + * mime = g_strdup ((const gchar *) data + 1); + * type = sep[1]; + * image_data = g_memdup (after, data + size - after); + * image_size = data + size - after; + + AUDDBG ("PIC: mime = %s, type = %d, desc = %s, size = %d.\n", * mime, + * type, * desc, * image_size); + return TRUE; +} + +static gboolean id3v22_read_image (VFSFile * handle, void * * image_data, gint * + image_size) +{ + gint version, header_size, data_size, footer_size, parsed; + gboolean syncsafe; + gsize offset; + gboolean found = FALSE; + + if (! read_header (handle, & version, & syncsafe, & offset, & header_size, + & data_size, & footer_size)) + return FALSE; + + for (parsed = 0; parsed < data_size && ! found; ) + { + gint frame_size, size, type; + gchar key[5]; + guchar * data; + gchar * mime, * desc; + + if (! read_frame (handle, data_size - parsed, version, syncsafe, + & frame_size, key, & data, & size)) + break; + + if (! strcmp (key, "PIC") && parse_pic (data, size, & mime, & type, + & desc, image_data, image_size)) + { + g_free (mime); + g_free (desc); + + if (type == 3) /* album cover */ + found = TRUE; + else if (type == 0) /* iTunes */ + found = TRUE; + else if (*image_data != NULL) + { + g_free(*image_data); + *image_data = NULL; + } + } + + g_free (data); + parsed += frame_size; + } + + return found; +} + +static void free_frame_cb (mowgli_dictionary_elem_t * element, void * unused) +{ + free_generic_frame (element->data); +} + +static void free_frame_dictionary (void) +{ + mowgli_dictionary_destroy (frames, free_frame_cb, NULL); + frames = NULL; +} + +static gboolean id3v22_write_tag (Tuple * tuple, VFSFile * f) +{ + return FALSE; +} + +tag_module_t id3v24 = +{ + .name = "ID3v2.2", + .can_handle_file = id3v22_can_handle_file, + .read_tag = id3v22_read_tag, + .read_image = id3v22_read_image, + .write_tag = id3v22_write_tag, +}; diff --git a/src/libaudtag/id3/id3v22.h b/src/libaudtag/id3/id3v22.h new file mode 100644 index 0000000..2801d21 --- /dev/null +++ b/src/libaudtag/id3/id3v22.h @@ -0,0 +1,30 @@ +/* + * Copyright 2010 Tony Vroon + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 or version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#ifndef AUDTAG_ID3V22_H +#define AUDTAG_ID3V22_H + +#include "../audtag.h" +#include "../tag_module.h" +#include "../util.h" + +extern tag_module_t id3v22; + +#endif diff --git a/src/libaudtag/id3/id3v24.c b/src/libaudtag/id3/id3v24.c new file mode 100644 index 0000000..499048d --- /dev/null +++ b/src/libaudtag/id3/id3v24.c @@ -0,0 +1,1106 @@ +/* + * Copyright 2009 Paula Stanciu + * Copyright 2010 John Lindgren + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#include <glib.h> + +#include <libaudcore/audstrings.h> + +#include "id3v24.h" +#include "../util.h" + +enum +{ + ID3_ALBUM = 0, + ID3_TITLE, + ID3_COMPOSER, + ID3_COPYRIGHT, + ID3_DATE, + ID3_TIME, + ID3_LENGTH, + ID3_ARTIST, + ID3_TRACKNR, + ID3_YEAR, + ID3_GENRE, + ID3_COMMENT, + ID3_PRIVATE, + ID3_ENCODER, + ID3_RECORDING_TIME, + ID3_TXXX, + ID3_RVA2, + ID3_TAGS_NO +}; + +static const gchar * id3_frames[ID3_TAGS_NO] = {"TALB","TIT2","TCOM", "TCOP", + "TDAT", "TIME", "TLEN", "TPE1", "TRCK", "TYER","TCON", "COMM", "PRIV", "TSSE", + "TDRC", "TXXX", "RVA2"}; + +static const guchar PRIMARY_CLASS_MUSIC[16] = {0xBC, 0x7D, 0x60, 0xD1, 0x23, + 0xE3, 0xE2, 0x4B, 0x86, 0xA1, 0x48, 0xA4, 0x2A, 0x28, 0x44, 0x1E}; +static const guchar PRIMARY_CLASS_AUDIO[16] = {0x29, 0x0F, 0xCD, 0x01, 0x4E, + 0xDA, 0x57, 0x41, 0x89, 0x7B, 0x62, 0x75, 0xD5, 0x0C, 0x4F, 0x11}; +static const guchar SECONDARY_CLASS_AUDIOBOOK[16] = {0xEB, 0x6B, 0x23, 0xE0, + 0x81, 0xC2, 0xDE, 0x4E, 0xA3, 0x6D, 0x7A, 0xF7, 0x6A, 0x3D, 0x45, 0xB5}; +static const guchar SECONDARY_CLASS_SPOKENWORD[16] = {0x13, 0x2A, 0x17, 0x3A, + 0xD9, 0x2B, 0x31, 0x48, 0x83, 0x5B, 0x11, 0x4F, 0x6A, 0x95, 0x94, 0x3F}; +static const guchar SECONDARY_CLASS_NEWS[16] = {0x9B, 0xDB, 0x77, 0x66, 0xA0, + 0xE5, 0x63, 0x40, 0xA1, 0xAD, 0xAC, 0xEB, 0x52, 0x84, 0x0C, 0xF1}; +static const guchar SECONDARY_CLASS_TALKSHOW[16] = {0x67, 0x4A, 0x82, 0x1B, + 0x80, 0x3F, 0x3E, 0x4E, 0x9C, 0xDE, 0xF7, 0x36, 0x1B, 0x0F, 0x5F, 0x1B}; +static const guchar SECONDARY_CLASS_GAMES_CLIP[16] = {0x68, 0x33, 0x03, 0x00, + 0x09, 0x50, 0xC3, 0x4A, 0xA8, 0x20, 0x5D, 0x2D, 0x09, 0xA4, 0xE7, 0xC1}; +static const guchar SECONDARY_CLASS_GAMES_SONG[16] = {0x31, 0xF7, 0x4F, 0xF2, + 0xFC, 0x96, 0x0F, 0x4D, 0xA2, 0xF5, 0x5A, 0x34, 0x83, 0x68, 0x2B, 0x1A}; + +#pragma pack(push) /* must be byte-aligned */ +#pragma pack(1) +typedef struct +{ + gchar magic[3]; + guchar version; + guchar revision; + guchar flags; + guint32 size; +} +ID3v2Header; + +typedef struct +{ + gchar key[4]; + guint32 size; + guint16 flags; +} +ID3v2FrameHeader; +#pragma pack(pop) + +typedef struct +{ + gchar key[5]; + guchar * data; + gint size; +} +GenericFrame; + +#define ID3_HEADER_SYNCSAFE 0x80 +#define ID3_HEADER_HAS_EXTENDED_HEADER 0x40 +#define ID3_HEADER_HAS_FOOTER 0x10 + +#define ID3_FRAME_HAS_GROUP 0x0040 +#define ID3_FRAME_COMPRESSED 0x0008 +#define ID3_FRAME_ENCRYPTED 0x0004 +#define ID3_FRAME_SYNCSAFE 0x0002 +#define ID3_FRAME_HAS_LENGTH 0x0001 + +#define TAG_SIZE 1 + +static mowgli_dictionary_t * frames = NULL; +static mowgli_list_t * frameIDs = NULL; + +#define write_syncsafe_int32(x) vfs_fput_be32 (syncsafe32 (x)) + +static gboolean skip_extended_header_3 (VFSFile * handle, gint * _size) +{ + guint32 size; + + if (vfs_fread (& size, 1, 4, handle) != 4) + return FALSE; + + size = GUINT32_FROM_BE (size); + + AUDDBG ("Found v2.3 extended header, size = %d.\n", (gint) size); + + if (vfs_fseek (handle, size, SEEK_CUR)) + return FALSE; + + * _size = 4 + size; + return TRUE; +} + +static gboolean skip_extended_header_4 (VFSFile * handle, gint * _size) +{ + guint32 size; + + if (vfs_fread (& size, 1, 4, handle) != 4) + return FALSE; + + size = unsyncsafe32 (GUINT32_FROM_BE (size)); + + AUDDBG ("Found v2.4 extended header, size = %d.\n", (gint) size); + + if (vfs_fseek (handle, size - 4, SEEK_CUR)) + return FALSE; + + * _size = size; + return TRUE; +} + +static gboolean validate_header (ID3v2Header * header, gboolean is_footer) +{ + if (memcmp (header->magic, is_footer ? "3DI" : "ID3", 3)) + return FALSE; + + if ((header->version != 3 && header->version != 4) || header->revision != 0) + return FALSE; + + header->size = unsyncsafe32 (GUINT32_FROM_BE (header->size)); + + AUDDBG ("Found ID3v2 %s:\n", is_footer ? "footer" : "header"); + AUDDBG (" magic = %.3s\n", header->magic); + AUDDBG (" version = %d\n", (gint) header->version); + AUDDBG (" revision = %d\n", (gint) header->revision); + AUDDBG (" flags = %x\n", (gint) header->flags); + AUDDBG (" size = %d\n", (gint) header->size); + return TRUE; +} + +static gboolean read_header (VFSFile * handle, gint * version, gboolean * + syncsafe, gsize * offset, gint * header_size, gint * data_size, gint * + footer_size) +{ + ID3v2Header header, footer; + + if (vfs_fseek (handle, 0, SEEK_SET)) + return FALSE; + + if (vfs_fread (& header, 1, sizeof (ID3v2Header), handle) != sizeof + (ID3v2Header)) + return FALSE; + + if (validate_header (& header, FALSE)) + { + * offset = 0; + * version = header.version; + * header_size = sizeof (ID3v2Header); + * data_size = header.size; + + if (header.flags & ID3_HEADER_HAS_FOOTER) + { + if (vfs_fseek (handle, header.size, SEEK_CUR)) + return FALSE; + + if (vfs_fread (& footer, 1, sizeof (ID3v2Header), handle) != sizeof + (ID3v2Header)) + return FALSE; + + if (! validate_header (& footer, TRUE)) + return FALSE; + + * footer_size = sizeof (ID3v2Header); + } + else + * footer_size = 0; + } + else + { + gsize end = vfs_fsize (handle); + + if (end < 0) + return FALSE; + + if (vfs_fseek (handle, end - sizeof (ID3v2Header), SEEK_SET)) + return FALSE; + + if (vfs_fread (& footer, 1, sizeof (ID3v2Header), handle) != sizeof + (ID3v2Header)) + return FALSE; + + if (! validate_header (& footer, TRUE)) + return FALSE; + + * offset = end - 2 * sizeof (ID3v2Header) - footer.size; + * version = footer.version; + * header_size = sizeof (ID3v2Header); + * data_size = footer.size; + * footer_size = sizeof (ID3v2Header); + + if (vfs_fseek (handle, * offset, SEEK_SET)) + return FALSE; + + if (vfs_fread (& header, 1, sizeof (ID3v2Header), handle) != sizeof + (ID3v2Header)) + return FALSE; + + if (! validate_header (& header, FALSE)) + return FALSE; + } + + * syncsafe = (header.flags & ID3_HEADER_SYNCSAFE) ? TRUE : FALSE; + + if (header.flags & ID3_HEADER_HAS_EXTENDED_HEADER) + { + gint extended_size = 0; + + if (header.version == 3) + { + if (! skip_extended_header_3 (handle, & extended_size)) + return FALSE; + } + else if (header.version == 4) + { + if (! skip_extended_header_4 (handle, & extended_size)) + return FALSE; + } + + * header_size += extended_size; + * data_size -= extended_size; + } + + AUDDBG ("Offset = %d, header size = %d, data size = %d, footer size = " + "%d.\n", (gint) * offset, * header_size, * data_size, * footer_size); + + return TRUE; +} + +static gint unsyncsafe (guchar * data, gint size) +{ + guchar * get = data, * set = data; + + while (size --) + { + guchar c = * set ++ = * get ++; + + if (c == 0xff && size && ! get[0]) + { + size --; + get ++; + } + } + + return set - data; +} + +static gboolean read_frame (VFSFile * handle, gint max_size, gint version, + gboolean syncsafe, gint * frame_size, gchar * key, guchar * * data, gint * size) +{ + ID3v2FrameHeader header; + gint skip = 0; + + if ((max_size -= sizeof (ID3v2FrameHeader)) < 0) + return FALSE; + + if (vfs_fread (& header, 1, sizeof (ID3v2FrameHeader), handle) != sizeof + (ID3v2FrameHeader)) + return FALSE; + + if (! header.key[0]) /* padding */ + return FALSE; + + header.size = (version == 3) ? GUINT32_FROM_BE (header.size) : unsyncsafe32 + (GUINT32_FROM_BE (header.size)); + header.flags = GUINT16_FROM_BE (header.flags); + + if (header.size > max_size) + return FALSE; + + AUDDBG ("Found frame:\n"); + AUDDBG (" key = %.4s\n", header.key); + AUDDBG (" size = %d\n", (gint) header.size); + AUDDBG (" flags = %x\n", (gint) header.flags); + + * frame_size = sizeof (ID3v2FrameHeader) + header.size; + sprintf (key, "%.4s", header.key); + + if (header.flags & (ID3_FRAME_COMPRESSED | ID3_FRAME_ENCRYPTED)) + { + AUDDBG ("Hit compressed/encrypted frame %s.\n", key); + return FALSE; + } + + if (header.flags & ID3_FRAME_HAS_GROUP) + skip ++; + if (header.flags & ID3_FRAME_HAS_LENGTH) + skip += 4; + + if (skip > 0 && vfs_fseek (handle, skip, SEEK_CUR)) + return FALSE; + + * size = header.size - skip; + * data = g_malloc (* size); + + if (vfs_fread (* data, 1, * size, handle) != * size) + return FALSE; + + if (syncsafe || (header.flags & ID3_FRAME_SYNCSAFE)) + * size = unsyncsafe (* data, * size); + + AUDDBG ("Data size = %d.\n", * size); + return TRUE; +} + +static gchar * convert_text (const gchar * text, gint length, gint encoding, + gboolean nulled, gint * _converted, const gchar * * after) +{ + gchar * buffer = NULL; + gsize converted = 0; + + if (nulled) + { + const guchar null16[] = {0, 0}; + const gchar * null; + + switch (encoding) + { + case 0: + case 3: + if ((null = memchr (text, 0, length)) == NULL) + return NULL; + + length = null - text; + + if (after != NULL) + * after = null + 1; + + break; + case 1: + case 2: + if ((null = memfind (text, length, null16, 2)) == NULL) + return NULL; + + length = null - text; + + if (after != NULL) + * after = null + 2; + + break; + } + } + + switch (encoding) + { + case 0: + buffer = g_convert (text, length, "UTF-8", "ISO-8859-1", NULL, + & converted, NULL); + break; + case 1: + if (text[0] == (gchar) 0xff) + buffer = g_convert (text + 2, length - 2, "UTF-8", "UTF-16LE", NULL, + & converted, NULL); + else + buffer = g_convert (text + 2, length - 2, "UTF-8", "UTF-16BE", NULL, + & converted, NULL); + + break; + case 2: + buffer = g_convert (text, length, "UTF-8", "UTF-16BE", NULL, + & converted, NULL); + break; + case 3: + buffer = g_malloc (length + 1); + memcpy (buffer, text, length); + buffer[length] = 0; + converted = length; + break; + } + + if (_converted != NULL) + * _converted = converted; + + return buffer; +} + +static gchar * decode_text_frame (const guchar * data, gint size) +{ + return convert_text ((const gchar *) data + 1, size - 1, data[0], FALSE, + NULL, NULL); +} + +static gboolean decode_comment_frame (const guchar * _data, gint size, gchar * * + lang, gchar * * type, gchar * * value) +{ + const gchar * data = (const gchar *) _data; + gchar * pair, * sep; + gint converted; + + pair = convert_text (data + 4, size - 4, data[0], FALSE, & converted, NULL); + + if (pair == NULL || (sep = memchr (pair, 0, converted)) == NULL) + return FALSE; + + * lang = g_strndup (data + 1, 3); + * type = g_strdup (pair); + * value = g_strdup (sep + 1); + + g_free (pair); + return TRUE; +} + +static void free_generic_frame (GenericFrame * frame) +{ + g_free (frame->data); + g_free (frame); +} + +static void read_all_frames (VFSFile * handle, gint version, gboolean syncsafe, + gint data_size) +{ + gint pos; + + for (pos = 0; pos < data_size; ) + { + gint frame_size, size; + gchar key[5]; + guchar * data; + GenericFrame * frame; + + if (! read_frame (handle, data_size - pos, version, syncsafe, + & frame_size, key, & data, & size)) + break; + + frame = g_malloc (sizeof (GenericFrame)); + strcpy (frame->key, key); + frame->data = data; + frame->size = size; + + mowgli_dictionary_add (frames, frame->key, frame); + mowgli_node_add (frame->key, mowgli_node_create (), frameIDs); + + pos += frame_size; + } +} + +static gboolean write_frame (VFSFile * handle, GenericFrame * frame, gint * + frame_size) +{ + ID3v2FrameHeader header; + + memcpy (header.key, frame->key, 4); + header.size = syncsafe32 (frame->size); + header.size = GUINT32_TO_BE (header.size); + header.flags = 0; + + if (vfs_fwrite (& header, 1, sizeof (ID3v2FrameHeader), handle) != sizeof + (ID3v2FrameHeader)) + return FALSE; + + if (vfs_fwrite (frame->data, 1, frame->size, handle) != frame->size) + return FALSE; + + * frame_size = sizeof (ID3v2FrameHeader) + frame->size; + return TRUE; +} + +static guint32 writeAllFramesToFile (VFSFile * fd) +{ + guint32 size = 0; + mowgli_node_t *n, *tn; + MOWGLI_LIST_FOREACH_SAFE(n, tn, frameIDs->head) + { + GenericFrame *frame = (GenericFrame *) mowgli_dictionary_retrieve(frames, (gchar *) (n->data)); + if (frame) + { + gint frame_size; + + if (! write_frame (fd, frame, & frame_size)) + break; + + size += frame_size; + } + } + return size; +} + +static gboolean write_header (VFSFile * handle, gint size, gboolean is_footer) +{ + ID3v2Header header; + + memcpy (header.magic, is_footer ? "3DI" : "ID3", 3); + header.version = 4; + header.revision = 0; + header.flags = ID3_HEADER_HAS_FOOTER; + header.size = syncsafe32 (size); + header.size = GUINT32_TO_BE (header.size); + + return vfs_fwrite (& header, 1, sizeof (ID3v2Header), handle) == sizeof + (ID3v2Header); +} + +static gint get_frame_id (const gchar * key) +{ + gint id; + + for (id = 0; id < ID3_TAGS_NO; id ++) + { + if (! strcmp (key, id3_frames[id])) + return id; + } + + return -1; +} + +static void associate_string (Tuple * tuple, gint field, const gchar * + customfield, const guchar * data, gint size) +{ + gchar * text = decode_text_frame (data, size); + + if (text == NULL) + return; + + if (customfield != NULL) + AUDDBG ("Custom field %s = %s.\n", customfield, text); + else + AUDDBG ("Field %i = %s.\n", field, text); + + tuple_associate_string (tuple, field, customfield, text); + g_free (text); +} + +static void associate_int (Tuple * tuple, gint field, const gchar * + customfield, const guchar * data, gint size) +{ + gchar * text = decode_text_frame (data, size); + + if (text == NULL) + return; + + if (customfield != NULL) + AUDDBG ("Custom field %s = %s.\n", customfield, text); + else + AUDDBG ("Field %i = %s.\n", field, text); + + tuple_associate_int (tuple, field, customfield, atoi (text)); + g_free (text); +} + +static void decode_private_info (Tuple * tuple, const guchar * data, gint size) +{ + gchar * text = g_strndup ((const gchar *) data, size); + + if (!strncmp(text, "WM/", 3)) + { + gchar *separator = strchr(text, 0); + if (separator == NULL) + goto DONE; + + gchar * value = separator + 1; + if (!strncmp(text, "WM/MediaClassPrimaryID", 22)) + { + if (!memcmp(value, PRIMARY_CLASS_MUSIC, 16)) + tuple_associate_string (tuple, -1, "media-class", "Music"); + if (!memcmp(value, PRIMARY_CLASS_AUDIO, 16)) + tuple_associate_string (tuple, -1, "media-class", "Audio (non-music)"); + } else if (!strncmp(text, "WM/MediaClassSecondaryID", 24)) + { + if (!memcmp(value, SECONDARY_CLASS_AUDIOBOOK, 16)) + tuple_associate_string (tuple, -1, "media-class", "Audio Book"); + if (!memcmp(value, SECONDARY_CLASS_SPOKENWORD, 16)) + tuple_associate_string (tuple, -1, "media-class", "Spoken Word"); + if (!memcmp(value, SECONDARY_CLASS_NEWS, 16)) + tuple_associate_string (tuple, -1, "media-class", "News"); + if (!memcmp(value, SECONDARY_CLASS_TALKSHOW, 16)) + tuple_associate_string (tuple, -1, "media-class", "Talk Show"); + if (!memcmp(value, SECONDARY_CLASS_GAMES_CLIP, 16)) + tuple_associate_string (tuple, -1, "media-class", "Game Audio (clip)"); + if (!memcmp(value, SECONDARY_CLASS_GAMES_SONG, 16)) + tuple_associate_string (tuple, -1, "media-class", "Game Soundtrack"); + } else { + AUDDBG("Unrecognised tag %s (Windows Media) ignored\n", text); + } + } else { + AUDDBG("Unable to decode private data, skipping: %s\n", text); + } + +DONE: + g_free (text); +} + +static void decode_comment (Tuple * tuple, const guchar * data, gint size) +{ + gchar * lang, * type, * value; + + if (! decode_comment_frame (data, size, & lang, & type, & value)) + return; + + AUDDBG ("Comment: lang = %s, type = %s, value = %s.\n", lang, type, value); + + if (! type[0]) /* blank type == actual comment */ + tuple_associate_string (tuple, FIELD_COMMENT, NULL, value); + + g_free (lang); + g_free (type); + g_free (value); +} + +static void decode_txxx (Tuple * tuple, const guchar * data, gint size) +{ + gchar * text = decode_text_frame (data, size); + + if (text == NULL) + return; + + gchar *separator = strchr(text, 0); + + if (separator == NULL) + return; + + gchar * value = separator + 1; + AUDDBG ("TXXX: %s = %s.\n", text, value); + tuple_associate_string (tuple, -1, text, value); + + g_free (text); +} + +static gboolean decode_rva2_block (const guchar * * _data, gint * _size, gint * + channel, gint * adjustment, gint * adjustment_unit, gint * peak, gint * + peak_unit) +{ + const guchar * data = * _data; + gint size = * _size; + gint peak_bits; + + if (size < 4) + return FALSE; + + * channel = data[0]; + * adjustment = (gchar) data[1]; /* first byte is signed */ + * adjustment = (* adjustment << 8) | data[2]; + * adjustment_unit = 512; + peak_bits = data[3]; + + data += 4; + size -= 4; + + AUDDBG ("RVA2 block: channel = %d, adjustment = %d/%d, peak bits = %d\n", + * channel, * adjustment, * adjustment_unit, peak_bits); + + if (peak_bits > 0 && peak_bits < sizeof (gint) * 8) + { + gint bytes = (peak_bits + 7) / 8; + gint count; + + if (bytes > size) + return FALSE; + + * peak = 0; + * peak_unit = 1 << peak_bits; + + for (count = 0; count < bytes; count ++) + * peak = (* peak << 8) | data[count]; + + data += bytes; + size -= count; + + AUDDBG ("RVA2 block: peak = %d/%d\n", * peak, * peak_unit); + } + else + { + * peak = 0; + * peak_unit = 0; + } + + * _data = data; + * _size = size; + return TRUE; +} + +static void decode_rva2 (Tuple * tuple, const guchar * data, gint size) +{ + const gchar * domain; + gint channel, adjustment, adjustment_unit, peak, peak_unit; + + if (memchr (data, 0, size) == NULL) + return; + + domain = (const gchar *) data; + + AUDDBG ("RVA2 domain: %s\n", domain); + + size -= strlen (domain) + 1; + data += strlen (domain) + 1; + + while (size > 0) + { + if (! decode_rva2_block (& data, & size, & channel, & adjustment, + & adjustment_unit, & peak, & peak_unit)) + break; + + if (channel != 1) /* specific channel? */ + continue; + + if (tuple_get_value_type (tuple, FIELD_GAIN_GAIN_UNIT, NULL) == + TUPLE_INT) + adjustment = adjustment * (gint64) tuple_get_int (tuple, + FIELD_GAIN_GAIN_UNIT, NULL) / adjustment_unit; + else + tuple_associate_int (tuple, FIELD_GAIN_GAIN_UNIT, NULL, + adjustment_unit); + + if (peak_unit) + { + if (tuple_get_value_type (tuple, FIELD_GAIN_PEAK_UNIT, NULL) == + TUPLE_INT) + peak = peak * (gint64) tuple_get_int (tuple, + FIELD_GAIN_PEAK_UNIT, NULL) / peak_unit; + else + tuple_associate_int (tuple, FIELD_GAIN_PEAK_UNIT, NULL, + peak_unit); + } + + if (! strcasecmp (domain, "album")) + { + tuple_associate_int (tuple, FIELD_GAIN_ALBUM_GAIN, NULL, adjustment); + + if (peak_unit) + tuple_associate_int (tuple, FIELD_GAIN_ALBUM_PEAK, NULL, peak); + } + else if (! strcasecmp (domain, "track")) + { + tuple_associate_int (tuple, FIELD_GAIN_TRACK_GAIN, NULL, adjustment); + + if (peak_unit) + tuple_associate_int (tuple, FIELD_GAIN_TRACK_PEAK, NULL, peak); + } + } +} + +static void decode_genre (Tuple * tuple, const guchar * data, gint size) +{ + gint numericgenre; + gchar * text = decode_text_frame (data, size); + + if (text == NULL) + return; + + if (text[0] == '(') + numericgenre = atoi (text + 1); + else + numericgenre = atoi (text); + + if (numericgenre > 0) + { + tuple_associate_string(tuple, FIELD_GENRE, NULL, convert_numericgenre_to_text(numericgenre)); + return; + } + tuple_associate_string(tuple, FIELD_GENRE, NULL, text); + g_free (text); + return; +} + +static GenericFrame * add_generic_frame (gint id, gint size) +{ + GenericFrame * frame = mowgli_dictionary_retrieve (frames, id3_frames[id]); + + if (frame == NULL) + { + frame = g_malloc (sizeof (GenericFrame)); + strcpy (frame->key, id3_frames[id]); + mowgli_dictionary_add (frames, frame->key, frame); + mowgli_node_add (frame->key, mowgli_node_create (), frameIDs); + } + else + g_free (frame->data); + + frame->data = g_malloc (size); + frame->size = size; + return frame; +} + +static void add_text_frame (gint id, const gchar * text) +{ + gint length = strlen (text); + GenericFrame * frame = add_generic_frame (id, length + 1); + + frame->data[0] = 3; /* UTF-8 encoding */ + memcpy (frame->data + 1, text, length); +} + +static void add_comment_frame (const gchar * text) +{ + gint length = strlen (text); + GenericFrame * frame = add_generic_frame (ID3_COMMENT, length + 5); + + frame->data[0] = 3; /* UTF-8 encoding */ + strcpy ((gchar *) frame->data + 1, "eng"); /* well, it *might* be English */ + memcpy (frame->data + 5, text, length); +} + +static void add_frameFromTupleStr (Tuple * tuple, int field, int id3_field) +{ + add_text_frame (id3_field, tuple_get_string (tuple, field, NULL)); +} + +static void add_frameFromTupleInt (Tuple * tuple, int field, int id3_field) +{ + gchar scratch[16]; + + snprintf (scratch, sizeof scratch, "%d", tuple_get_int (tuple, field, NULL)); + add_text_frame (id3_field, scratch); +} + +static gboolean id3v24_can_handle_file (VFSFile * handle) +{ + gint version, header_size, data_size, footer_size; + gboolean syncsafe; + gsize offset; + + return read_header (handle, & version, & syncsafe, & offset, & header_size, + & data_size, & footer_size); +} + +static gboolean id3v24_read_tag (Tuple * tuple, VFSFile * handle) +{ + gint version, header_size, data_size, footer_size; + gboolean syncsafe; + gsize offset; + gint pos; + + if (! read_header (handle, & version, & syncsafe, & offset, & header_size, + & data_size, & footer_size)) + return FALSE; + + for (pos = 0; pos < data_size; ) + { + gint frame_size, size, id; + gchar key[5]; + guchar * data; + + if (! read_frame (handle, data_size - pos, version, syncsafe, + & frame_size, key, & data, & size)) + break; + + id = get_frame_id (key); + + switch (id) + { + case ID3_ALBUM: + associate_string (tuple, FIELD_ALBUM, NULL, data, size); + break; + case ID3_TITLE: + associate_string (tuple, FIELD_TITLE, NULL, data, size); + break; + case ID3_COMPOSER: + associate_string (tuple, FIELD_COMPOSER, NULL, data, size); + break; + case ID3_COPYRIGHT: + associate_string (tuple, FIELD_COPYRIGHT, NULL, data, size); + break; + case ID3_DATE: + associate_string (tuple, FIELD_DATE, NULL, data, size); + break; + case ID3_TIME: + associate_int (tuple, FIELD_LENGTH, NULL, data, size); + break; + case ID3_LENGTH: + associate_int (tuple, FIELD_LENGTH, NULL, data, size); + break; + case ID3_ARTIST: + associate_string (tuple, FIELD_ARTIST, NULL, data, size); + break; + case ID3_TRACKNR: + associate_int (tuple, FIELD_TRACK_NUMBER, NULL, data, size); + break; + case ID3_YEAR: + case ID3_RECORDING_TIME: + associate_int (tuple, FIELD_YEAR, NULL, data, size); + break; + case ID3_GENRE: + decode_genre (tuple, data, size); + break; + case ID3_COMMENT: + decode_comment (tuple, data, size); + break; + case ID3_PRIVATE: + decode_private_info (tuple, data, size); + break; + case ID3_ENCODER: + associate_string (tuple, -1, "encoder", data, size); + break; + case ID3_TXXX: + decode_txxx (tuple, data, size); + break; + case ID3_RVA2: + decode_rva2 (tuple, data, size); + break; + default: + AUDDBG ("Ignoring unsupported ID3 frame %s.\n", key); + break; + } + + g_free (data); + pos += frame_size; + } + + return TRUE; +} + +static gboolean parse_apic (const guchar * data, gint size, gchar * * mime, + gint * type, gchar * * desc, void * * image_data, gint * image_size) +{ + const guchar * sep; + const guchar * after; + + if (size < 2 || (sep = memchr (data + 1, 0, size - 2)) == NULL) + return FALSE; + + if ((* desc = convert_text ((const gchar *) sep + 2, data + size - sep - 2, + data[0], TRUE, NULL, (const gchar * *) & after)) == NULL) + return FALSE; + + * mime = g_strdup ((const gchar *) data + 1); + * type = sep[1]; + * image_data = g_memdup (after, data + size - after); + * image_size = data + size - after; + + AUDDBG ("APIC: mime = %s, type = %d, desc = %s, size = %d.\n", * mime, + * type, * desc, * image_size); + return TRUE; +} + +static gboolean id3v24_read_image (VFSFile * handle, void * * image_data, gint * + image_size) +{ + gint version, header_size, data_size, footer_size, parsed; + gboolean syncsafe; + gsize offset; + gboolean found = FALSE; + + if (! read_header (handle, & version, & syncsafe, & offset, & header_size, + & data_size, & footer_size)) + return FALSE; + + for (parsed = 0; parsed < data_size && ! found; ) + { + gint frame_size, size, type; + gchar key[5]; + guchar * data; + gchar * mime, * desc; + + if (! read_frame (handle, data_size - parsed, version, syncsafe, + & frame_size, key, & data, & size)) + break; + + if (! strcmp (key, "APIC") && parse_apic (data, size, & mime, & type, + & desc, image_data, image_size)) + { + g_free (mime); + g_free (desc); + + if (type == 3) /* album cover */ + found = TRUE; + else if (type == 0) /* iTunes */ + found = TRUE; + else if (*image_data != NULL) + { + g_free(*image_data); + *image_data = NULL; + } + } + + g_free (data); + parsed += frame_size; + } + + return found; +} + +static void free_frame_cb (mowgli_dictionary_elem_t * element, void * unused) +{ + free_generic_frame (element->data); +} + +static void free_frame_dictionary (void) +{ + mowgli_dictionary_destroy (frames, free_frame_cb, NULL); + frames = NULL; +} + +static gboolean id3v24_write_tag (Tuple * tuple, VFSFile * f) +{ + gint version, header_size, data_size, footer_size; + gboolean syncsafe; + gsize offset; + + if (! read_header (f, & version, & syncsafe, & offset, & header_size, + & data_size, & footer_size)) + return FALSE; + + if (frameIDs != NULL) + { + mowgli_node_t *n, *tn; + MOWGLI_LIST_FOREACH_SAFE(n, tn, frameIDs->head) + { + mowgli_node_delete(n, frameIDs); + } + } + frameIDs = mowgli_list_create(); + + //read all frames into generic frames; + frames = mowgli_dictionary_create(strcasecmp); + read_all_frames (f, version, syncsafe, data_size); + + //make the new frames from tuple and replace in the dictionary the old frames with the new ones + if (tuple_get_string(tuple, FIELD_ARTIST, NULL)) + add_frameFromTupleStr(tuple, FIELD_ARTIST, ID3_ARTIST); + + if (tuple_get_string(tuple, FIELD_TITLE, NULL)) + add_frameFromTupleStr(tuple, FIELD_TITLE, ID3_TITLE); + + if (tuple_get_string(tuple, FIELD_ALBUM, NULL)) + add_frameFromTupleStr(tuple, FIELD_ALBUM, ID3_ALBUM); + + if (tuple_get_string (tuple, FIELD_COMMENT, NULL) != NULL) + add_comment_frame (tuple_get_string (tuple, FIELD_COMMENT, NULL)); + + if (tuple_get_string(tuple, FIELD_GENRE, NULL)) + add_frameFromTupleStr(tuple, FIELD_GENRE, ID3_GENRE); + + if (tuple_get_int(tuple, FIELD_YEAR, NULL) != 0) + add_frameFromTupleInt(tuple, FIELD_YEAR, ID3_YEAR); + + if (tuple_get_int(tuple, FIELD_TRACK_NUMBER, NULL) != 0) + add_frameFromTupleInt(tuple, FIELD_TRACK_NUMBER, ID3_TRACKNR); + + if (! offset) + { + if (! cut_beginning_tag (f, header_size + data_size + footer_size)) + return FALSE; + } + else + { + if (offset + header_size + data_size + footer_size != vfs_fsize (f)) + return FALSE; + + if (vfs_ftruncate (f, offset)) + return FALSE; + } + + offset = vfs_fsize (f); + + if (offset < 0 || vfs_fseek (f, offset, SEEK_SET) || ! write_header (f, 0, + FALSE)) + return FALSE; + + data_size = writeAllFramesToFile (f); + free_frame_dictionary (); + + if (! write_header (f, data_size, TRUE) || vfs_fseek (f, offset, SEEK_SET) + || ! write_header (f, data_size, FALSE)) + return FALSE; + + return TRUE; +} + +tag_module_t id3v24 = +{ + .name = "ID3v2.3/4", + .can_handle_file = id3v24_can_handle_file, + .read_tag = id3v24_read_tag, + .read_image = id3v24_read_image, + .write_tag = id3v24_write_tag, +}; diff --git a/src/libaudtag/id3/id3v24.h b/src/libaudtag/id3/id3v24.h new file mode 100644 index 0000000..1fdb3db --- /dev/null +++ b/src/libaudtag/id3/id3v24.h @@ -0,0 +1,30 @@ +/* + * Copyright 2010 John Lindgren + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 2 or version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + +#ifndef AUDTAG_ID3V2_H +#define AUDTAG_ID3V2_H + +#include "../audtag.h" +#include "../tag_module.h" +#include "../util.h" + +extern tag_module_t id3v24; + +#endif diff --git a/src/libaudtag/tag_module.c b/src/libaudtag/tag_module.c index e1b110f..e8c8b3f 100644 --- a/src/libaudtag/tag_module.c +++ b/src/libaudtag/tag_module.c @@ -1,30 +1,66 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + #include <glib.h> #include <libaudcore/tuple.h> #include <libaudcore/vfs.h> + +#include "audtag.h" #include "util.h" #include "tag_module.h" #include "wma/module.h" -#include "id3/id3.h" +#include "id3/id3v1.h" +#include "id3/id3v24.h" #include "ape/ape.h" -#include "aac/aac.h" +/* #include "aac/aac.h" */ void init_tag_modules(void) { - mowgli_node_add(&wma, mowgli_node_create(), &tag_modules); - mowgli_node_add(&id3, mowgli_node_create(), &tag_modules); - mowgli_node_add(&ape, mowgli_node_create(), &tag_modules); - mowgli_node_add(&aac, mowgli_node_create(), &tag_modules); + mowgli_node_add((void *)&id3v24, &id3v24.node, &tag_modules); + mowgli_node_add((void *)&ape, &ape.node, &tag_modules); + mowgli_node_add((void *)&id3v1, &id3v1.node, &tag_modules); } -tag_module_t *find_tag_module(VFSFile * fd) +tag_module_t * find_tag_module (VFSFile * fd, gint new_type) { - mowgli_node_t *mod, *tmod; - MOWGLI_LIST_FOREACH_SAFE(mod, tmod, tag_modules.head) - { - vfs_fseek(fd,0,SEEK_SET); - if (((tag_module_t*)(mod->data))->can_handle_file(fd)) - return (tag_module_t*)(mod->data); - } + mowgli_node_t *mod, *tmod; + MOWGLI_LIST_FOREACH_SAFE(mod, tmod, tag_modules.head) + { + if (vfs_fseek(fd, 0, SEEK_SET)) + { + AUDDBG("not a seekable file\n"); + return NULL; + } + if (((tag_module_t *) (mod->data))->can_handle_file(fd)) + return (tag_module_t *) (mod->data); + } + + /* No existing tag; see if we can create a new one. */ + if (new_type != TAG_TYPE_NONE) + { + MOWGLI_LIST_FOREACH_SAFE (mod, tmod, tag_modules.head) + { + if (((tag_module_t *) (mod->data))->type == new_type) + return mod->data; + } + } AUDDBG("no module found\n"); return NULL; diff --git a/src/libaudtag/tag_module.h b/src/libaudtag/tag_module.h index f25af42..2edfd9c 100644 --- a/src/libaudtag/tag_module.h +++ b/src/libaudtag/tag_module.h @@ -1,3 +1,23 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + /* Interface of the tagging library */ #ifndef TAG_MODULE_H @@ -9,21 +29,26 @@ G_BEGIN_DECLS #include <mowgli.h> #include "libaudcore/tuple.h" #include "libaudcore/vfs.h" - + mowgli_list_t tag_modules; int number_of_modules; typedef Tuple* pTuple; typedef struct _module { + gchar *name; + gint type; /* set to TAG_TYPE_NONE if the module cannot create new tags */ gboolean(*can_handle_file) (VFSFile *fd); - pTuple(*populate_tuple_from_file)(Tuple *tuple, VFSFile* fd); - gboolean(*write_tuple_to_file) (Tuple * tuple, VFSFile *fd); + gboolean (* read_tag) (Tuple * tuple, VFSFile * handle); + gboolean (* read_image) (VFSFile * handle, void * * data, gint * size); + gboolean (* write_tag) (Tuple * tuple, VFSFile * handle); + + mowgli_node_t node; } tag_module_t; /* this function must be modified when including new modules */ void init_tag_modules(void); -tag_module_t *find_tag_module(VFSFile *fd); +tag_module_t * find_tag_module (VFSFile * handle, gint new_type); G_END_DECLS #endif /* TAG_MODULE_H */ diff --git a/src/libaudtag/util.c b/src/libaudtag/util.c index c7e06be..d1c0bea 100644 --- a/src/libaudtag/util.c +++ b/src/libaudtag/util.c @@ -1,3 +1,23 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + #include <glib.h> #include "util.h" #include <inttypes.h> @@ -11,17 +31,14 @@ time_t unix_time(guint64 win_time) guint16 get_year(guint64 win_time) { - GDate* d = g_date_new(); + GDate *d = g_date_new(); g_date_set_time_t(d, unix_time(win_time)); guint16 year = g_date_get_year(d); g_date_free(d); return year; } -Tuple *makeTuple(Tuple *tuple, const gchar* title, const gchar* artist, - const gchar* comment, const gchar* album, - const gchar * genre, const gchar* year, - const gchar* filePath, int tracnr) +Tuple *makeTuple(Tuple * tuple, const gchar * title, const gchar * artist, const gchar * comment, const gchar * album, const gchar * genre, const gchar * year, const gchar * filePath, int tracnr) { tuple_associate_string(tuple, FIELD_ARTIST, NULL, artist); @@ -35,11 +52,11 @@ Tuple *makeTuple(Tuple *tuple, const gchar* title, const gchar* artist, return tuple; } -const gchar* get_complete_filepath(Tuple *tuple) +const gchar *get_complete_filepath(Tuple * tuple) { - const gchar* filepath; - const gchar* dir; - const gchar* file; + const gchar *filepath; + const gchar *dir; + const gchar *file; dir = tuple_get_string(tuple, FIELD_FILE_PATH, NULL); file = tuple_get_string(tuple, FIELD_FILE_NAME, NULL); @@ -48,31 +65,31 @@ const gchar* get_complete_filepath(Tuple *tuple) return filepath; } -void print_tuple(Tuple *tuple) +void print_tuple(Tuple * tuple) { #if WMA_DEBUG AUDDBG("--------------TUPLE PRINT --------------------\n"); - const gchar* title = tuple_get_string(tuple, FIELD_TITLE, NULL); + const gchar *title = tuple_get_string(tuple, FIELD_TITLE, NULL); AUDDBG("title = %s\n", title); /* artist */ - const gchar* artist = tuple_get_string(tuple, FIELD_ARTIST, NULL); + const gchar *artist = tuple_get_string(tuple, FIELD_ARTIST, NULL); AUDDBG("artist = %s\n", artist); /* copyright */ - const gchar* copyright = tuple_get_string(tuple, FIELD_COPYRIGHT, NULL); + const gchar *copyright = tuple_get_string(tuple, FIELD_COPYRIGHT, NULL); AUDDBG("copyright = %s\n", copyright); /* comment / description */ - const gchar* comment = tuple_get_string(tuple, FIELD_COMMENT, NULL); + const gchar *comment = tuple_get_string(tuple, FIELD_COMMENT, NULL); AUDDBG("comment = %s\n", comment); /* codec name */ - const gchar* codec_name = tuple_get_string(tuple, FIELD_CODEC, NULL); + const gchar *codec_name = tuple_get_string(tuple, FIELD_CODEC, NULL); AUDDBG("codec = %s\n", codec_name); /* album */ - const gchar* album = tuple_get_string(tuple, FIELD_ALBUM, NULL); + const gchar *album = tuple_get_string(tuple, FIELD_ALBUM, NULL); AUDDBG("Album = %s\n", album); /*track number */ @@ -80,7 +97,7 @@ void print_tuple(Tuple *tuple) AUDDBG("Track nr = %d\n", track_nr); /* genre */ - const gchar* genre = tuple_get_string(tuple, FIELD_GENRE, NULL); + const gchar *genre = tuple_get_string(tuple, FIELD_GENRE, NULL); AUDDBG("Genre = %s \n", genre); /* length */ @@ -92,50 +109,40 @@ void print_tuple(Tuple *tuple) AUDDBG("Year = %d\n", year); /* quality */ - const gchar* quality = tuple_get_string(tuple, FIELD_QUALITY, NULL); + const gchar *quality = tuple_get_string(tuple, FIELD_QUALITY, NULL); AUDDBG("quality = %s\n", quality); /* path */ - const gchar* path = tuple_get_string(tuple, FIELD_FILE_PATH, NULL); + const gchar *path = tuple_get_string(tuple, FIELD_FILE_PATH, NULL); AUDDBG("path = %s\n", path); /* filename */ - const gchar* filename = tuple_get_string(tuple, FIELD_FILE_NAME, NULL); + const gchar *filename = tuple_get_string(tuple, FIELD_FILE_NAME, NULL); AUDDBG("filename = %s\n", filename); AUDDBG("-----------------END---------------------\n"); #endif } -void seek(VFSFile *f, long pos) -{ - - vfs_fseek(f, pos, SEEK_SET); -} - -void skip(VFSFile *f, int amount) +gchar *read_char_data(VFSFile * fd, int size) { - vfs_fseek(f, amount, SEEK_CUR); -} - -gchar *read_char_data(VFSFile *fd, int size) -{ - gchar *value = g_new0(gchar, size); + gchar *value = g_new0(gchar, size + 1); vfs_fread(value, size, 1, fd); return value; } -gboolean write_char_data(VFSFile *f, gchar *data, size_t i) +gboolean write_char_data(VFSFile * f, gchar * data, size_t i) { - return (vfs_fwrite(data, i, 1, f) == i); + return (vfs_fwrite(data, i, 1, f) == i); } -gchar* utf8(gunichar2* s) + +gchar *utf8(gunichar2 * s) { g_return_val_if_fail(s != NULL, NULL); return g_utf16_to_utf8(s, -1, NULL, NULL, NULL); } -gunichar2 *fread_utf16(VFSFile* f, guint64 size) +gunichar2 *fread_utf16(VFSFile * f, guint64 size) { gunichar2 *p = (gunichar2 *) g_malloc0(size); if (vfs_fread(p, 1, size, f) != size) @@ -143,18 +150,18 @@ gunichar2 *fread_utf16(VFSFile* f, guint64 size) g_free(p); p = NULL; } - gchar * s = utf8(p); + gchar *s = utf8(p); AUDDBG("Converted to UTF8: '%s'\n", s); g_free(s); return p; } -gboolean write_utf16(VFSFile *f, gunichar2 *data, size_t i) +gboolean write_utf16(VFSFile * f, gunichar2 * data, size_t i) { - return (vfs_fwrite(data, i, 1, f) == i); + return (vfs_fwrite(data, i, 1, f) == i); } -guint8 read_uint8(VFSFile *fd) +guint8 read_uint8(VFSFile * fd) { guint16 i; if (vfs_fread(&i, 1, 1, fd) == 1) @@ -164,102 +171,90 @@ guint8 read_uint8(VFSFile *fd) return -1; } -guint16 read_LEuint16(VFSFile *fd) +guint16 read_LEuint16(VFSFile * fd) { guint16 a; if (vfs_fget_le16(&a, fd)) - { - AUDDBG("read_LEuint16 %d\n", a); return a; - } else + else return -1; } -guint16 read_BEuint16(VFSFile *fd) +guint16 read_BEuint16(VFSFile * fd) { guint16 a; if (vfs_fget_be16(&a, fd)) - { - AUDDBG("read_BEuint16 %d\n", a); return a; - } else + else return -1; } -guint32 read_LEuint32(VFSFile *fd) +guint32 read_LEuint32(VFSFile * fd) { guint32 a; if (vfs_fget_le32(&a, fd)) - { - AUDDBG("read_LEuint32 %d\n", a); return a; - } else + else return -1; } -guint32 read_BEuint32(VFSFile *fd) +guint32 read_BEuint32(VFSFile * fd) { guint32 a; if (vfs_fget_be32(&a, fd)) - { - AUDDBG("read_BEuint32 %d\n", a); return a; - } else + else return -1; } -guint64 read_LEuint64(VFSFile *fd) +guint64 read_LEuint64(VFSFile * fd) { guint64 a; if (vfs_fget_le64(&a, fd)) - { - AUDDBG("read_LEuint64 %"PRId64"\n", a); return a; - } else + else return -1; } -guint64 read_BEuint64(VFSFile *fd) +guint64 read_BEuint64(VFSFile * fd) { guint64 a; if (vfs_fget_be64(&a, fd)) - { - AUDDBG("read_BEuint14 %"PRId64"\n", a); return a; - } else + else return 1; } -gboolean write_uint8(VFSFile *fd, guint8 val) +gboolean write_uint8(VFSFile * fd, guint8 val) { return (vfs_fwrite(&val, 1, 1, fd) == 1); } -gboolean write_LEuint16(VFSFile *fd, guint16 val) +gboolean write_LEuint16(VFSFile * fd, guint16 val) { guint16 le_val = GUINT32_TO_LE(val); return (vfs_fwrite(&le_val, 2, 1, fd) == 2); } -gboolean write_BEuint32(VFSFile *fd, guint32 val) +gboolean write_BEuint32(VFSFile * fd, guint32 val) { guint32 be_val = GUINT32_TO_BE(val); return (vfs_fwrite(&be_val, 4, 1, fd) == 4); } -gboolean write_LEuint32(VFSFile *fd, guint32 val) +gboolean write_LEuint32(VFSFile * fd, guint32 val) { guint32 le_val = GUINT32_TO_LE(val); return (vfs_fwrite(&le_val, 4, 1, fd) == 4); } -gboolean write_LEuint64(VFSFile *fd, guint64 val) +gboolean write_LEuint64(VFSFile * fd, guint64 val) { guint64 le_val = GUINT64_TO_LE(val); return (vfs_fwrite(&le_val, 8, 1, fd) == 8); } -void copyAudioToFile(VFSFile *from, VFSFile *to, guint32 pos) +void copyAudioToFile(VFSFile * from, VFSFile * to, guint32 pos) { vfs_fseek(from, pos, SEEK_SET); while (vfs_feof(from) == 0) @@ -270,7 +265,7 @@ void copyAudioToFile(VFSFile *from, VFSFile *to, guint32 pos) } } -void copyAudioData(VFSFile* from, VFSFile *to, guint32 pos_from, guint32 pos_to) +void copyAudioData(VFSFile * from, VFSFile * to, guint32 pos_from, guint32 pos_to) { vfs_fseek(from, pos_from, SEEK_SET); int bytes_read = pos_from; @@ -289,3 +284,193 @@ void copyAudioData(VFSFile* from, VFSFile *to, guint32 pos_from, guint32 pos_to) vfs_fwrite(buf2, nn, 1, to); } } + +gboolean cut_beginning_tag (VFSFile * handle, gsize tag_size) +{ + guchar buffer[16384]; + gsize offset = 0, readed; + + if (! tag_size) + return TRUE; + + do + { + if (vfs_fseek (handle, offset + tag_size, SEEK_SET)) + return FALSE; + + readed = vfs_fread (buffer, 1, sizeof buffer, handle); + + if (vfs_fseek (handle, offset, SEEK_SET)) + return FALSE; + + if (vfs_fwrite (buffer, 1, readed, handle) != readed) + return FALSE; + + offset += readed; + } + while (readed); + + return vfs_ftruncate (handle, offset) == 0; +} + +gchar *convert_numericgenre_to_text(gint numericgenre) +{ + const struct + { + gint numericgenre; + gchar *genre; + } + table[] = + { + {GENRE_BLUES, "Blues"}, + {GENRE_CLASSIC_ROCK, "Classic Rock"}, + {GENRE_COUNTRY, "Country"}, + {GENRE_DANCE, "Dance"}, + {GENRE_DISCO, "Disco"}, + {GENRE_FUNK, "Funk"}, + {GENRE_GRUNGE, "Grunge"}, + {GENRE_HIPHOP, "Hip-Hop"}, + {GENRE_JAZZ, "Jazz"}, + {GENRE_METAL, "Metal"}, + {GENRE_NEW_AGE, "New Age"}, + {GENRE_OLDIES, "Oldies"}, + {GENRE_OTHER, "Other"}, + {GENRE_POP, "Pop"}, + {GENRE_R_B, "R&B"}, + {GENRE_RAP, "Rap"}, + {GENRE_REGGAE, "Reggae"}, + {GENRE_ROCK, "Rock"}, + {GENRE_TECHNO, "Techno"}, + {GENRE_INDUSTRIAL, "Industrial"}, + {GENRE_ALTERNATIVE, "Alternative"}, + {GENRE_SKA, "Ska"}, + {GENRE_DEATH_METAL, "Death Metal"}, + {GENRE_PRANKS, "Pranks"}, + {GENRE_SOUNDTRACK, "Soundtrack"}, + {GENRE_EURO_TECHNO, "Euro-Techno"}, + {GENRE_AMBIENT, "Ambient"}, + {GENRE_TRIP_HOP, "Trip-Hop"}, + {GENRE_VOCAL, "Vocal"}, + {GENRE_JAZZ_FUNK, "Jazz+Funk"}, + {GENRE_FUSION, "Fusion"}, + {GENRE_TRANCE, "Trance"}, + {GENRE_CLASSICAL, "Classical"}, + {GENRE_INSTRUMENTAL, "Instrumental"}, + {GENRE_ACID, "Acid"}, + {GENRE_HOUSE, "House"}, + {GENRE_GAME, "Game"}, + {GENRE_SOUND_CLIP, "Sound Clip"}, + {GENRE_GOSPEL, "Gospel"}, + {GENRE_NOISE, "Noise"}, + {GENRE_ALTERNROCK, "AlternRock"}, + {GENRE_BASS, "Bass"}, + {GENRE_SOUL, "Soul"}, + {GENRE_PUNK, "Punk"}, + {GENRE_SPACE, "Space"}, + {GENRE_MEDITATIVE, "Meditative"}, + {GENRE_INSTRUMENTAL_POP, "Instrumental Pop"}, + {GENRE_INSTRUMENTAL_ROCK, "Instrumental Rock"}, + {GENRE_ETHNIC, "Ethnic"}, + {GENRE_GOTHIC, "Gothic"}, + {GENRE_DARKWAVE, "Darkwave"}, + {GENRE_TECHNO_INDUSTRIAL, "Techno-Industrial"}, + {GENRE_ELECTRONIC, "Electronic"}, + {GENRE_POP_FOLK, "Pop-Folk"}, + {GENRE_EURODANCE, "Eurodance"}, + {GENRE_DREAM, "Dream"}, + {GENRE_SOUTHERN_ROCK, "Southern Rock"}, + {GENRE_COMEDY, "Comedy"}, + {GENRE_CULT, "Cult"}, + {GENRE_GANGSTA, "Gangsta"}, + {GENRE_TOP40, "Top 40"}, + {GENRE_CHRISTIAN_RAP, "Christian Rap"}, + {GENRE_POP_FUNK, "Pop/Funk"}, + {GENRE_JUNGLE, "Jungle"}, + {GENRE_NATIVE_AMERICAN, "Native American"}, + {GENRE_CABARET, "Cabaret"}, + {GENRE_NEW_WAVE, "New Wave"}, + {GENRE_PSYCHADELIC, "Psychadelic"}, + {GENRE_RAVE, "Rave"}, + {GENRE_SHOWTUNES, "Showtunes"}, + {GENRE_TRAILER, "Trailer"}, + {GENRE_LO_FI, "Lo-Fi"}, + {GENRE_TRIBAL, "Tribal"}, + {GENRE_ACID_PUNK, "Acid Punk"}, + {GENRE_ACID_JAZZ, "Acid Jazz"}, + {GENRE_POLKA, "Polka"}, + {GENRE_RETRO, "Retro"}, + {GENRE_MUSICAL, "Musical"}, + {GENRE_ROCK_ROLL, "Rock & Roll"}, + {GENRE_HARD_ROCK, "Hard Rock"}, + {GENRE_FOLK, "Folk"}, + {GENRE_FOLK_ROCK, "Folk-Rock"}, + {GENRE_NATIONAL_FOLK, "National Folk"}, + {GENRE_SWING, "Swing"}, + {GENRE_FAST_FUSION, "Fast Fusion"}, + {GENRE_BEBOB, "Bebob"}, + {GENRE_LATIN, "Latin"}, + {GENRE_REVIVAL, "Revival"}, + {GENRE_CELTIC, "Celtic"}, + {GENRE_BLUEGRASS, "Bluegrass"}, + {GENRE_AVANTGARDE, "Avantgarde"}, + {GENRE_GOTHIC_ROCK, "Gothic Rock"}, + {GENRE_PROGRESSIVE_ROCK, "Progressive Rock"}, + {GENRE_PSYCHEDELIC_ROCK, "Psychedelic Rock"}, + {GENRE_SYMPHONIC_ROCK, "Symphonic Rock"}, + {GENRE_SLOW_ROCK, "Slow Rock"}, + {GENRE_BIG_BAND, "Big Band"}, + {GENRE_CHORUS, "Chorus"}, + {GENRE_EASY_LISTENING, "Easy Listening"}, + {GENRE_ACOUSTIC, "Acoustic"}, + {GENRE_HUMOUR, "Humour"}, + {GENRE_SPEECH, "Speech"}, + {GENRE_CHANSON, "Chanson"}, + {GENRE_OPERA, "Opera"}, + {GENRE_CHAMBER_MUSIC, "Chamber Music"}, + {GENRE_SONATA, "Sonata"}, + {GENRE_SYMPHONY, "Symphony"}, + {GENRE_BOOTY_BASS, "Booty Bass"}, + {GENRE_PRIMUS, "Primus"}, + {GENRE_PORN_GROOVE, "Porn Groove"}, + {GENRE_SATIRE, "Satire"}, + {GENRE_SLOW_JAM, "Slow Jam"}, + {GENRE_CLUB, "Club"}, + {GENRE_TANGO, "Tango"}, + {GENRE_SAMBA, "Samba"}, + {GENRE_FOLKLORE, "Folklore"}, + {GENRE_BALLAD, "Ballad"}, + {GENRE_POWER_BALLAD, "Power Ballad"}, + {GENRE_RHYTHMIC_SOUL, "Rhythmic Soul"}, + {GENRE_FREESTYLE, "Freestyle"}, + {GENRE_DUET, "Duet"}, + {GENRE_PUNK_ROCK, "Punk Rock"}, + {GENRE_DRUM_SOLO, "Drum Solo"}, + {GENRE_A_CAPELLA, "A capella"}, + {GENRE_EURO_HOUSE, "Euro-House"}, + }; + + gint count; + + for (count = 0; count < G_N_ELEMENTS(table); count++) + { + if (table[count].numericgenre == numericgenre) + { + return table[count].genre; + } + } + + return "Unknown"; +} + +guint32 unsyncsafe32 (guint32 x) +{ + return (x & 0x7f) | ((x & 0x7f00) >> 1) | ((x & 0x7f0000) >> 2) | ((x & + 0x7f000000) >> 3); +} + +guint32 syncsafe32 (guint32 x) +{ + return (x & 0x7f) | ((x & 0x3f80) << 1) | ((x & 0x1fc000) << 2) | ((x & + 0xfe00000) << 3); +} + diff --git a/src/libaudtag/util.h b/src/libaudtag/util.h index 5b6918a..0e6a4f3 100644 --- a/src/libaudtag/util.h +++ b/src/libaudtag/util.h @@ -1,3 +1,23 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + #ifndef TAGUTIL_H #define TAGUTIL_H @@ -6,10 +26,136 @@ #include "libaudcore/tuple.h" #include "libaudcore/vfs.h" -#define WMA_DEBUG 1 - #define BROKEN 1 +enum { + GENRE_BLUES = 0, + GENRE_CLASSIC_ROCK, + GENRE_COUNTRY, + GENRE_DANCE, + GENRE_DISCO, + GENRE_FUNK, + GENRE_GRUNGE, + GENRE_HIPHOP, + GENRE_JAZZ, + GENRE_METAL, + GENRE_NEW_AGE, + GENRE_OLDIES, + GENRE_OTHER, + GENRE_POP, + GENRE_R_B, + GENRE_RAP, + GENRE_REGGAE, + GENRE_ROCK, + GENRE_TECHNO, + GENRE_INDUSTRIAL, + GENRE_ALTERNATIVE, + GENRE_SKA, + GENRE_DEATH_METAL, + GENRE_PRANKS, + GENRE_SOUNDTRACK, + GENRE_EURO_TECHNO, + GENRE_AMBIENT, + GENRE_TRIP_HOP, + GENRE_VOCAL, + GENRE_JAZZ_FUNK, + GENRE_FUSION, + GENRE_TRANCE, + GENRE_CLASSICAL, + GENRE_INSTRUMENTAL, + GENRE_ACID, + GENRE_HOUSE, + GENRE_GAME, + GENRE_SOUND_CLIP, + GENRE_GOSPEL, + GENRE_NOISE, + GENRE_ALTERNROCK, + GENRE_BASS, + GENRE_SOUL, + GENRE_PUNK, + GENRE_SPACE, + GENRE_MEDITATIVE, + GENRE_INSTRUMENTAL_POP, + GENRE_INSTRUMENTAL_ROCK, + GENRE_ETHNIC, + GENRE_GOTHIC, + GENRE_DARKWAVE, + GENRE_TECHNO_INDUSTRIAL, + GENRE_ELECTRONIC, + GENRE_POP_FOLK, + GENRE_EURODANCE, + GENRE_DREAM, + GENRE_SOUTHERN_ROCK, + GENRE_COMEDY, + GENRE_CULT, + GENRE_GANGSTA, + GENRE_TOP40, + GENRE_CHRISTIAN_RAP, + GENRE_POP_FUNK, + GENRE_JUNGLE, + GENRE_NATIVE_AMERICAN, + GENRE_CABARET, + GENRE_NEW_WAVE, + GENRE_PSYCHADELIC, + GENRE_RAVE, + GENRE_SHOWTUNES, + GENRE_TRAILER, + GENRE_LO_FI, + GENRE_TRIBAL, + GENRE_ACID_PUNK, + GENRE_ACID_JAZZ, + GENRE_POLKA, + GENRE_RETRO, + GENRE_MUSICAL, + GENRE_ROCK_ROLL, + GENRE_HARD_ROCK, + GENRE_FOLK, + GENRE_FOLK_ROCK, + GENRE_NATIONAL_FOLK, + GENRE_SWING, + GENRE_FAST_FUSION, + GENRE_BEBOB, + GENRE_LATIN, + GENRE_REVIVAL, + GENRE_CELTIC, + GENRE_BLUEGRASS, + GENRE_AVANTGARDE, + GENRE_GOTHIC_ROCK, + GENRE_PROGRESSIVE_ROCK, + GENRE_PSYCHEDELIC_ROCK, + GENRE_SYMPHONIC_ROCK, + GENRE_SLOW_ROCK, + GENRE_BIG_BAND, + GENRE_CHORUS, + GENRE_EASY_LISTENING, + GENRE_ACOUSTIC, + GENRE_HUMOUR, + GENRE_SPEECH, + GENRE_CHANSON, + GENRE_OPERA, + GENRE_CHAMBER_MUSIC, + GENRE_SONATA, + GENRE_SYMPHONY, + GENRE_BOOTY_BASS, + GENRE_PRIMUS, + GENRE_PORN_GROOVE, + GENRE_SATIRE, + GENRE_SLOW_JAM, + GENRE_CLUB, + GENRE_TANGO, + GENRE_SAMBA, + GENRE_FOLKLORE, + GENRE_BALLAD, + GENRE_POWER_BALLAD, + GENRE_RHYTHMIC_SOUL, + GENRE_FREESTYLE, + GENRE_DUET, + GENRE_PUNK_ROCK, + GENRE_DRUM_SOLO, + GENRE_A_CAPELLA, + GENRE_EURO_HOUSE +}; + time_t unix_time(guint64 win_time); guint16 get_year(guint64 win_time); @@ -50,9 +196,15 @@ gboolean write_LEuint64(VFSFile *fd, guint64 val); guint64 read_LEint64(VFSFile *fd); void copyAudioToFile(VFSFile *from, VFSFile *to, guint32 pos); void copyAudioData(VFSFile* from, VFSFile *to, guint32 pos_from, guint32 pos_to); +gboolean cut_beginning_tag (VFSFile * handle, gsize tag_size); + +gchar *convert_numericgenre_to_text(gint numericgenre); + +guint32 unsyncsafe32 (guint32 x); +guint32 syncsafe32 (guint32 x); /* macro for debug print */ -#ifdef WMA_DEBUG +#ifdef DEBUG # define AUDDBG(...) do { g_print("%s:%d %s(): ", __FILE__, (int)__LINE__, __FUNCTION__); g_print(__VA_ARGS__); } while (0) #else # define AUDDBG(...) do { } while (0) diff --git a/src/libaudtag/wma/guid.c b/src/libaudtag/wma/guid.c index 734b9ee..473c138 100644 --- a/src/libaudtag/wma/guid.c +++ b/src/libaudtag/wma/guid.c @@ -1,3 +1,23 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + /* this stuff may be moved to ../util.h if needed by other formats */ #include <inttypes.h> @@ -7,10 +27,11 @@ #include "guid.h" #include "wma_fmt.h" -GUID * guid_read_from_file(VFSFile * f) { +GUID *guid_read_from_file(VFSFile * f) +{ GUID temp; - if ((f == NULL) || (vfs_fread(&temp, sizeof (GUID), 1, f) != 1)) + if ((f == NULL) || (vfs_fread(&temp, sizeof(GUID), 1, f) != 1)) return NULL; temp.le32 = GUINT32_FROM_LE(temp.le32); @@ -18,42 +39,40 @@ GUID * guid_read_from_file(VFSFile * f) { temp.le16_2 = GUINT16_FROM_LE(temp.le16_2); temp.be64 = GUINT64_FROM_BE(temp.be64); - return g_memdup(& temp, sizeof (GUID)); + return g_memdup(&temp, sizeof(GUID)); } -gboolean guid_write_to_file(VFSFile * f, int guid_type) { +gboolean guid_write_to_file(VFSFile * f, int guid_type) +{ g_return_val_if_fail(f != NULL, FALSE); GUID *g = guid_convert_from_string(wma_guid_map(guid_type)); - gboolean ret = write_LEuint32(f, g->le32) && - write_LEuint16(f, g->le16_1) && - write_LEuint16(f, g->le16_1) && - write_LEuint64(f, g->be64); + gboolean ret = write_LEuint32(f, g->le32) && write_LEuint16(f, g->le16_1) && write_LEuint16(f, g->le16_1) && write_LEuint64(f, g->be64); g_free(g); return ret; } -GUID *guid_convert_from_string(const gchar * string) { +GUID *guid_convert_from_string(const gchar * string) +{ GUID temp; - if (sscanf(string, "%" SCNx32 "-%" SCNx16 "-%" SCNx16 "-%" SCNx64, - & temp.le32, & temp.le16_1, & temp.le16_2, & temp.be64) != 4) + if (sscanf(string, "%" SCNx32 "-%" SCNx16 "-%" SCNx16 "-%" SCNx64, &temp.le32, &temp.le16_1, &temp.le16_2, &temp.be64) != 4) return NULL; - return g_memdup(& temp, sizeof (GUID)); + return g_memdup(&temp, sizeof(GUID)); } -gchar *guid_convert_to_string(const GUID* g) { +gchar *guid_convert_to_string(const GUID * g) +{ - return g_strdup_printf("%8x-%hx-%hx-%"PRIx64"\n", GUINT32_TO_LE(g->le32), - GUINT16_TO_LE(g->le16_1), GUINT16_TO_LE(g->le16_2), - GUINT64_TO_BE(g->be64)); + return g_strdup_printf("%8x-%hx-%hx-%" PRIx64 "\n", GUINT32_TO_LE(g->le32), GUINT16_TO_LE(g->le16_1), GUINT16_TO_LE(g->le16_2), GUINT64_TO_BE(g->be64)); } -gboolean guid_equal(GUID *g1, GUID *g2) { +gboolean guid_equal(GUID * g1, GUID * g2) +{ /* - AUDDBG("GUID 1 = %8x-%hx-%hx-%"PRIx64"\n", g1->le32, g1->le16_1, g1->le16_2, g1->be64); - AUDDBG("GUID 2 = %8x-%hx-%hx-%"PRIx64"\n", g2->le32, g2->le16_1, g2->le16_2, g2->be64); + AUDDBG("GUID 1 = %8x-%hx-%hx-%"PRIx64"\n", g1->le32, g1->le16_1, g1->le16_2, g1->be64); + AUDDBG("GUID 2 = %8x-%hx-%hx-%"PRIx64"\n", g2->le32, g2->le16_1, g2->le16_2, g2->be64); */ g_return_val_if_fail((g1 != NULL) && (g2 != NULL), FALSE); @@ -67,7 +86,8 @@ gboolean guid_equal(GUID *g1, GUID *g2) { return FALSE; } -int get_guid_type(GUID *g) { +int get_guid_type(GUID * g) +{ GUID *g1; int i; for (i = 0; i < ASF_OBJECT_LAST - 1; i++) @@ -83,25 +103,26 @@ int get_guid_type(GUID *g) { return -1; } -const gchar *wma_guid_map(int i) { - const gchar * _guid_map[ASF_OBJECT_LAST] = { - ASF_HEADER_OBJECT_GUID, - ASF_FILE_PROPERTIES_OBJECT_GUID, - ASF_STREAM_PROPERTIES_OBJECT_GUID, - ASF_HEADER_EXTENSION_OBJECT_GUID, - ASF_CODEC_LIST_OBJECT_GUID, - ASF_SCRIPT_COMMAND_OBJECT_GUID, - ASF_MARKER_OBJECT_GUID, - ASF_BITRATE_MUTUAL_EXCLUSION_OBJECT_GUID, - ASF_ERROR_CORRECTION_OBJECT_GUID, - ASF_CONTENT_DESCRIPTION_OBJECT_GUID, - ASF_EXTENDED_CONTENT_DESCRIPTION_OBJECT_GUID, - ASF_CONTENT_BRANDING_OBJECT_GUID, - ASF_STREAM_BITRATE_PROPERTIES_OBJECT_GUID, - ASF_CONTENT_ENCRYPTION_OBJECT_GUID, - ASF_EXTENDED_CONTENT_ENCRYPTION_OBJECT_GUID, - ASF_DIGITAL_SIGNATURE_OBJECT_GUID, - ASF_PADDING_OBJECT_GUID +const gchar *wma_guid_map(int i) +{ + const gchar *_guid_map[ASF_OBJECT_LAST] = { + ASF_HEADER_OBJECT_GUID, + ASF_FILE_PROPERTIES_OBJECT_GUID, + ASF_STREAM_PROPERTIES_OBJECT_GUID, + ASF_HEADER_EXTENSION_OBJECT_GUID, + ASF_CODEC_LIST_OBJECT_GUID, + ASF_SCRIPT_COMMAND_OBJECT_GUID, + ASF_MARKER_OBJECT_GUID, + ASF_BITRATE_MUTUAL_EXCLUSION_OBJECT_GUID, + ASF_ERROR_CORRECTION_OBJECT_GUID, + ASF_CONTENT_DESCRIPTION_OBJECT_GUID, + ASF_EXTENDED_CONTENT_DESCRIPTION_OBJECT_GUID, + ASF_CONTENT_BRANDING_OBJECT_GUID, + ASF_STREAM_BITRATE_PROPERTIES_OBJECT_GUID, + ASF_CONTENT_ENCRYPTION_OBJECT_GUID, + ASF_EXTENDED_CONTENT_ENCRYPTION_OBJECT_GUID, + ASF_DIGITAL_SIGNATURE_OBJECT_GUID, + ASF_PADDING_OBJECT_GUID }; return _guid_map[i]; } diff --git a/src/libaudtag/wma/guid.h b/src/libaudtag/wma/guid.h index e14284b..1bb193a 100644 --- a/src/libaudtag/wma/guid.h +++ b/src/libaudtag/wma/guid.h @@ -1,3 +1,23 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + #ifndef _GUID_H #define _GUID_H diff --git a/src/libaudtag/wma/module.h b/src/libaudtag/wma/module.h index 99d9a6a..62670cb 100644 --- a/src/libaudtag/wma/module.h +++ b/src/libaudtag/wma/module.h @@ -1,6 +1,29 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + #ifndef TAG_WMA_MODULE_H #define TAG_WMA_MODULE_H #include "../tag_module.h" +#include "wma.h" + extern tag_module_t wma; + #endif diff --git a/src/libaudtag/wma/wma.c b/src/libaudtag/wma/wma.c index 6605d16..67d5752 100644 --- a/src/libaudtag/wma/wma.c +++ b/src/libaudtag/wma/wma.c @@ -1,3 +1,23 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + #include <inttypes.h> #include <glib-2.0/glib/gstdio.h> #include <libaudcore/tuple.h> @@ -8,17 +28,16 @@ #include "module.h" #include "../util.h" -tag_module_t wma = {wma_can_handle_file, wma_populate_tuple_from_file, wma_write_tuple_to_file}; - /* static functions */ -static GenericHeader *read_generic_header(VFSFile*f, gboolean read_data) { +static GenericHeader *read_generic_header(VFSFile * f, gboolean read_data) +{ AUDDBG("read top-level header object\n"); g_return_val_if_fail((f != NULL), NULL); GenericHeader *header = g_new0(GenericHeader, 1); header->guid = guid_read_from_file(f); header->size = read_LEuint64(f); if (read_data) - header->data = (gchar*) read_char_data(f, header->size); + header->data = (gchar *) read_char_data(f, header->size); else header->data = NULL; @@ -29,7 +48,8 @@ static GenericHeader *read_generic_header(VFSFile*f, gboolean read_data) { return header; } -static HeaderObj *read_top_header_object(VFSFile *f) { +static HeaderObj *read_top_header_object(VFSFile * f) +{ AUDDBG("read top-level header object\n"); g_return_val_if_fail((f != NULL), NULL); HeaderObj *header = g_new0(HeaderObj, 1); @@ -52,7 +72,8 @@ static HeaderObj *read_top_header_object(VFSFile *f) { return header; } -static ContentDescrObj *read_content_descr_obj(VFSFile *f) { +static ContentDescrObj *read_content_descr_obj(VFSFile * f) +{ ContentDescrObj *cdo = g_new0(ContentDescrObj, 1); cdo->guid = guid_read_from_file(f); cdo->size = read_LEuint64(f); @@ -69,7 +90,8 @@ static ContentDescrObj *read_content_descr_obj(VFSFile *f) { return cdo; } -static ExtContentDescrObj *read_ext_content_descr_obj(VFSFile *f, Tuple* t, gboolean populate_tuple) { +static ExtContentDescrObj *read_ext_content_descr_obj(VFSFile * f, Tuple * t, gboolean populate_tuple) +{ ExtContentDescrObj *ecdo = g_new0(ExtContentDescrObj, 1); ecdo->guid = guid_read_from_file(f); ecdo->size = read_LEuint64(f); @@ -78,10 +100,11 @@ static ExtContentDescrObj *read_ext_content_descr_obj(VFSFile *f, Tuple* t, gboo return ecdo; } -static guint find_descriptor_id(gchar* s) { +static guint find_descriptor_id(gchar * s) +{ AUDDBG("finding descriptor id for '%s'\n", s); g_return_val_if_fail(s != NULL, -1); - gchar * l[DESC_LAST] = {DESC_ALBUM_STR, DESC_YEAR_STR, DESC_GENRE_STR, DESC_TRACK_STR}; + gchar *l[DESC_LAST] = { DESC_ALBUM_STR, DESC_YEAR_STR, DESC_GENRE_STR, DESC_TRACK_STR }; guint i; for (i = 0; i < DESC_LAST; i++) if (!strcmp(l[i], s)) @@ -92,7 +115,8 @@ static guint find_descriptor_id(gchar* s) { return -1; } -static ContentDescriptor *read_descriptor(VFSFile *f, Tuple *t, gboolean populate_tuple) { +static ContentDescriptor *read_descriptor(VFSFile * f, Tuple * t, gboolean populate_tuple) +{ ContentDescriptor *cd = g_new0(ContentDescriptor, 1); gchar *val = NULL, *name = NULL; guint32 intval = -1; @@ -114,9 +138,9 @@ static ContentDescriptor *read_descriptor(VFSFile *f, Tuple *t, gboolean populat if (populate_tuple) { - /*we only parse int's and UTF strings, everything else is handled as raw data*/ + /*we only parse int's and UTF strings, everything else is handled as raw data */ if (cd->val_type == 0) - {/*UTF16*/ + { /*UTF16 */ cd->val = read_char_data(f, cd->val_len); val = utf8((gunichar2 *) cd->val); AUDDBG("val: '%s' dtype: %d\n", val, dtype); @@ -128,7 +152,8 @@ static ContentDescriptor *read_descriptor(VFSFile *f, Tuple *t, gboolean populat tuple_associate_int(t, FIELD_TRACK_NUMBER, NULL, atoi(val)); if (dtype == DESC_YEAR) tuple_associate_int(t, FIELD_YEAR, NULL, atoi(val)); - } else + } + else { if (cd->val_type == 3) { @@ -136,27 +161,31 @@ static ContentDescriptor *read_descriptor(VFSFile *f, Tuple *t, gboolean populat AUDDBG("intval: %d, dtype: %d\n", intval, dtype); if (dtype == DESC_TRACK) tuple_associate_int(t, FIELD_TRACK_NUMBER, NULL, intval); - } else + } + else cd->val = read_char_data(f, cd->val_len); } - } else + } + else cd->val = read_char_data(f, cd->val_len); AUDDBG("read str_val: '%s', intval: %d\n", val, intval); AUDDBG("exiting read_descriptor \n\n"); return cd; } -static ContentDescriptor **read_descriptors(VFSFile *f, guint count, Tuple* t, gboolean populate_tuple) { +static ContentDescriptor **read_descriptors(VFSFile * f, guint count, Tuple * t, gboolean populate_tuple) +{ if (count == 0) return NULL; - ContentDescriptor **descs = g_new0(ContentDescriptor*, count); + ContentDescriptor **descs = g_new0(ContentDescriptor *, count); int i; for (i = 0; i < count; i++) descs[i] = read_descriptor(f, t, populate_tuple); return descs; } -void free_content_descr_obj(ContentDescrObj* c) { +void free_content_descr_obj(ContentDescrObj * c) +{ g_free(c->guid); g_free(c->title); g_free(c->author); @@ -166,13 +195,15 @@ void free_content_descr_obj(ContentDescrObj* c) { g_free(c); } -void free_content_descr(ContentDescriptor *cd) { +void free_content_descr(ContentDescriptor * cd) +{ g_free(cd->name); g_free(cd->val); g_free(cd); } -void free_ext_content_descr_obj(ExtContentDescrObj *ecdo) { +void free_ext_content_descr_obj(ExtContentDescrObj * ecdo) +{ int i; g_free(ecdo->guid); for (i = 0; i < ecdo->content_desc_count; i++) @@ -181,7 +212,8 @@ void free_ext_content_descr_obj(ExtContentDescrObj *ecdo) { } /* returns the offset of the object in the file */ -static long ftell_object_by_guid(VFSFile *f, GUID *g) { +static long ftell_object_by_guid(VFSFile * f, GUID * g) +{ AUDDBG("seeking object %s, with ID %d \n", guid_convert_to_string(g), get_guid_type(g)); HeaderObj *h = read_top_header_object(f); g_return_val_if_fail((f != NULL) && (g != NULL) && (h != NULL), -1); @@ -190,17 +222,16 @@ static long ftell_object_by_guid(VFSFile *f, GUID *g) { while (i < h->objectsNr) { GenericHeader *gen_hdr = read_generic_header(f, FALSE); - AUDDBG("encountered GUID %s, with ID %d\n", - guid_convert_to_string(gen_hdr->guid), get_guid_type(gen_hdr->guid)); + AUDDBG("encountered GUID %s, with ID %d\n", guid_convert_to_string(gen_hdr->guid), get_guid_type(gen_hdr->guid)); if (guid_equal(gen_hdr->guid, g)) { g_free(h); g_free(gen_hdr); guint64 ret = vfs_ftell(f) - 24; - AUDDBG("at offset %"PRIx64"\n", ret); + AUDDBG("at offset %" PRIx64 "\n", ret); return ret; } - vfs_fseek(f, gen_hdr->size - 24, SEEK_CUR); //most headers have a size as their second field" + vfs_fseek(f, gen_hdr->size - 24, SEEK_CUR); //most headers have a size as their second field" i++; } AUDDBG("The object was not found\n"); @@ -208,21 +239,24 @@ static long ftell_object_by_guid(VFSFile *f, GUID *g) { return -1; } -VFSFile *make_temp_file() { - /* create a temporary file*/ +VFSFile *make_temp_file() +{ + /* create a temporary file */ const gchar *tmpdir = g_get_tmp_dir(); gchar *tmp_path = g_strdup_printf("file://%s/%s", tmpdir, "wmatmp.wma"); return vfs_fopen(tmp_path, "w+"); } -long ftell_object_by_str(VFSFile *f, gchar *s) { - GUID* g = guid_convert_from_string(s); +long ftell_object_by_str(VFSFile * f, gchar * s) +{ + GUID *g = guid_convert_from_string(s); long res = ftell_object_by_guid(f, g); g_free(g); return res; } -static void write_content_descr_obj_from_tuple(VFSFile *f, ContentDescrObj *cdo, Tuple* t) { +static void write_content_descr_obj_from_tuple(VFSFile * f, ContentDescrObj * cdo, Tuple * t) +{ glong size; gboolean free_cdo = FALSE; if (cdo == NULL) @@ -231,66 +265,64 @@ static void write_content_descr_obj_from_tuple(VFSFile *f, ContentDescrObj *cdo, free_cdo = TRUE; } - cdo->title = g_utf8_to_utf16(tuple_get_string(t, FIELD_TITLE, NULL), - -1, NULL, &size, NULL); + cdo->title = g_utf8_to_utf16(tuple_get_string(t, FIELD_TITLE, NULL), -1, NULL, &size, NULL); cdo->title_length = 2 * (size + 1); - cdo->author = g_utf8_to_utf16(tuple_get_string(t, FIELD_ARTIST, NULL), - -1, NULL, &size, NULL); + cdo->author = g_utf8_to_utf16(tuple_get_string(t, FIELD_ARTIST, NULL), -1, NULL, &size, NULL); cdo->author_length = 2 * (size + 1); - cdo->copyright = g_utf8_to_utf16(tuple_get_string(t, FIELD_COPYRIGHT, NULL), - -1, NULL, &size, NULL); + cdo->copyright = g_utf8_to_utf16(tuple_get_string(t, FIELD_COPYRIGHT, NULL), -1, NULL, &size, NULL); cdo->copyright_length = 2 * (size + 1); - cdo->description = g_utf8_to_utf16(tuple_get_string(t, FIELD_COMMENT, NULL), - -1, NULL, &size, NULL); + cdo->description = g_utf8_to_utf16(tuple_get_string(t, FIELD_COMMENT, NULL), -1, NULL, &size, NULL); cdo->desc_length = 2 * (size + 1); - cdo->size = 34 + cdo->title_length + cdo->author_length + - cdo->copyright_length + cdo->desc_length; + cdo->size = 34 + cdo->title_length + cdo->author_length + cdo->copyright_length + cdo->desc_length; guid_write_to_file(f, ASF_CONTENT_DESCRIPTION_OBJECT); write_LEuint64(f, cdo->size); write_LEuint16(f, cdo->title_length); write_LEuint16(f, cdo->author_length); write_LEuint16(f, cdo->copyright_length); write_LEuint16(f, cdo->desc_length); - write_LEuint16(f, 2); // rating_length = 2 + write_LEuint16(f, 2); // rating_length = 2 write_utf16(f, cdo->title, cdo->title_length); write_utf16(f, cdo->title, cdo->title_length); write_utf16(f, cdo->author, cdo->author_length); write_utf16(f, cdo->copyright, cdo->copyright_length); write_utf16(f, cdo->description, cdo->desc_length); - write_utf16(f, NULL, 2); //rating == NULL + write_utf16(f, NULL, 2); //rating == NULL if (free_cdo) free_content_descr_obj(cdo); } -static void write_ext_content_descr_obj_from_tuple(VFSFile *f, ExtContentDescrObj* ecdo, Tuple* tuple) { } +static void write_ext_content_descr_obj_from_tuple(VFSFile * f, ExtContentDescrObj * ecdo, Tuple * tuple) +{ +} -static gboolean write_generic_header(VFSFile *f, GenericHeader *gh) { +static gboolean write_generic_header(VFSFile * f, GenericHeader * gh) +{ AUDDBG("Writing generic header\n"); guid_write_to_file(f, get_guid_type(gh->guid)); return write_char_data(f, gh->data, gh->size); } -static void free_generic_header(GenericHeader *gh) { +static void free_generic_header(GenericHeader * gh) +{ g_free(gh->guid); g_free(gh->data); g_free(gh); } -static gboolean write_top_header_object(VFSFile *f, HeaderObj *header) { +static gboolean write_top_header_object(VFSFile * f, HeaderObj * header) +{ AUDDBG("write header object\n"); vfs_fseek(f, 0, SEEK_SET); - return (guid_write_to_file(f, ASF_HEADER_OBJECT) && - write_LEuint64(f, header->size) && - write_LEuint32(f, header->objectsNr) && - write_uint8(f, header->res1) && /* the reserved fields*/ + return (guid_write_to_file(f, ASF_HEADER_OBJECT) && write_LEuint64(f, header->size) && write_LEuint32(f, header->objectsNr) && write_uint8(f, header->res1) && /* the reserved fields */ write_uint8(f, header->res2)); } /* interface functions */ -gboolean wma_can_handle_file(VFSFile *f) { - GUID * guid1 = guid_read_from_file(f); - GUID * guid2 = guid_convert_from_string(ASF_HEADER_OBJECT_GUID); +gboolean wma_can_handle_file(VFSFile * f) +{ + GUID *guid1 = guid_read_from_file(f); + GUID *guid2 = guid_convert_from_string(ASF_HEADER_OBJECT_GUID); gboolean equal = ((guid1 != NULL) && guid_equal(guid1, guid2)); g_free(guid1); @@ -299,13 +331,14 @@ gboolean wma_can_handle_file(VFSFile *f) { return equal; } -Tuple *wma_populate_tuple_from_file(Tuple *t, VFSFile *f) { +gboolean wma_read_tag (Tuple * t, VFSFile * f) +{ gchar *artist = NULL, *title = NULL, *comment = NULL; print_tuple(t); gint seek_res = vfs_fseek(f, ftell_object_by_str(f, ASF_CONTENT_DESCRIPTION_OBJECT_GUID), SEEK_SET); if (seek_res == 0) - { //if the CONTENT_DESCRIPTION_OBJECT was found + { //if the CONTENT_DESCRIPTION_OBJECT was found ContentDescrObj *cdo = read_content_descr_obj(f); artist = utf8(cdo->author); title = utf8(cdo->title); @@ -316,27 +349,26 @@ Tuple *wma_populate_tuple_from_file(Tuple *t, VFSFile *f) { tuple_associate_string(t, FIELD_COMMENT, NULL, comment); } seek_res = vfs_fseek(f, ftell_object_by_str(f, ASF_EXTENDED_CONTENT_DESCRIPTION_OBJECT_GUID), SEEK_SET); - /*this populates the tuple with the attributes stored as extended descriptors*/ + /*this populates the tuple with the attributes stored as extended descriptors */ ExtContentDescrObj *ecdo = read_ext_content_descr_obj(f, t, TRUE); free_ext_content_descr_obj(ecdo); print_tuple(t); - return t; + return TRUE; } -gboolean wma_write_tuple_to_file(Tuple *tuple, VFSFile *f) { - - +gboolean wma_write_tag (Tuple * tuple, VFSFile * f) +{ #if BROKEN return FALSE; #endif HeaderObj *top_ho = read_top_header_object(f); - VFSFile * tmpfile = make_temp_file(); + VFSFile *tmpfile = make_temp_file(); gint i, cdo_pos, ecdo_pos; - GUID* g; - /*read all the headers and write them to the new file*/ - /*the headers that contain tuple data will be overwritten*/ - AUDDBG("Header Object size: %"PRId64"\n", top_ho->size); + GUID *g; + /*read all the headers and write them to the new file */ + /*the headers that contain tuple data will be overwritten */ + AUDDBG("Header Object size: %" PRId64 "\n", top_ho->size); //vfs_fseek(tmpfile, ) for (i = 0; i < top_ho->objectsNr; i++) { @@ -344,13 +376,14 @@ gboolean wma_write_tuple_to_file(Tuple *tuple, VFSFile *f) { g = guid_convert_from_string(ASF_CONTENT_DESCRIPTION_OBJECT_GUID); if (guid_equal(gh->guid, g)) { - write_content_descr_obj_from_tuple(tmpfile, (ContentDescrObj*) gh, tuple); + write_content_descr_obj_from_tuple(tmpfile, (ContentDescrObj *) gh, tuple); g_free(g); - } else + } + else { g = guid_convert_from_string(ASF_EXTENDED_CONTENT_DESCRIPTION_OBJECT_GUID); if (guid_equal(gh->guid, g)) - write_ext_content_descr_obj_from_tuple(tmpfile, (ExtContentDescrObj*) gh, tuple); + write_ext_content_descr_obj_from_tuple(tmpfile, (ExtContentDescrObj *) gh, tuple); else { write_generic_header(tmpfile, gh); @@ -359,7 +392,7 @@ gboolean wma_write_tuple_to_file(Tuple *tuple, VFSFile *f) { } free_generic_header(gh); } - /*check wether these headers existed in the original file*/ + /*check wether these headers existed in the original file */ cdo_pos = ftell_object_by_str(f, ASF_CONTENT_DESCRIPTION_OBJECT_GUID); ecdo_pos = ftell_object_by_str(f, ASF_EXTENDED_CONTENT_DESCRIPTION_OBJECT_GUID); if (cdo_pos == -1) @@ -374,21 +407,29 @@ gboolean wma_write_tuple_to_file(Tuple *tuple, VFSFile *f) { } write_top_header_object(tmpfile, top_ho); - gchar* f1 = g_filename_from_uri(tmpfile->uri, NULL, NULL); - gchar* f2 = g_filename_from_uri(f->uri, NULL, NULL); + gchar *f1 = g_filename_from_uri(tmpfile->uri, NULL, NULL); + gchar *f2 = g_filename_from_uri(f->uri, NULL, NULL); vfs_fclose(tmpfile); /* - if (g_rename(f1, f2) == 0) - { - AUDDBG("the tag was updated successfully\n"); - } - else - { - AUDDBG("an error has occured\n"); - } + if (g_rename(f1, f2) == 0) + { + AUDDBG("the tag was updated successfully\n"); + } + else + { + AUDDBG("an error has occured\n"); + } */ g_free(f1); g_free(f2); return TRUE; } + +tag_module_t wma = { + .name = "WMA", + .can_handle_file = wma_can_handle_file, + .read_tag = wma_read_tag, + .write_tag = wma_write_tag, +}; + diff --git a/src/libaudtag/wma/wma.h b/src/libaudtag/wma/wma.h index 9b45d08..756cee2 100644 --- a/src/libaudtag/wma/wma.h +++ b/src/libaudtag/wma/wma.h @@ -1,3 +1,23 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + #ifndef _WMA_H #define _WMA_H @@ -6,6 +26,7 @@ #include "libaudcore/vfs.h" #include "wma_fmt.h" +#ifndef TAG_WMA_MODULE_H /* static functions */ /* reads the whole structure, containing the data */ @@ -23,13 +44,11 @@ static ExtContentDescrObj *read_ext_content_descr_obj(VFSFile * f, Tuple *t, gbo static long ftell_object_by_guid(VFSFile *f, GUID *g); static long ftell_object_by_str(VFSFile *f, gchar *s); +#endif -/* interface functions*/ +/* TAG plugin API */ gboolean wma_can_handle_file(VFSFile *f); - -Tuple *wma_populate_tuple_from_file(Tuple *t, VFSFile *f); - -gboolean wma_write_tuple_to_file(Tuple *t, VFSFile *f); +gboolean wma_read_tag (Tuple * tuple, VFSFile * handle); +gboolean wma_write_tag (Tuple * tuple, VFSFile * handle); #endif /* _WMA_H */ - diff --git a/src/libaudtag/wma/wma_fmt.h b/src/libaudtag/wma/wma_fmt.h index 3b6bf64..c96517c 100644 --- a/src/libaudtag/wma/wma_fmt.h +++ b/src/libaudtag/wma/wma_fmt.h @@ -1,3 +1,23 @@ +/* + * Copyright 2009 Paula Stanciu + * + * This file is part of Audacious. + * + * Audacious is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, version 3 of the License. + * + * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Audacious. If not, see <http://www.gnu.org/licenses/>. + * + * The Audacious team does not consider modular code linking to Audacious or + * using our public API to be a derived work. + */ + #ifndef _WMA_FMT_H #define _WMA_FMT_H @@ -56,7 +76,7 @@ typedef enum { DESC_LAST } DescrIndexes; -/* +/* * this should be fine for all headers whose content is irrelevant, * but the size is needed so that we can skip it */ diff --git a/src/libeggsmclient/Makefile b/src/libeggsmclient/Makefile index fbe40e7..b124d60 100644 --- a/src/libeggsmclient/Makefile +++ b/src/libeggsmclient/Makefile @@ -18,4 +18,4 @@ include ../../buildsys.mk include ../../extra.mk CPPFLAGS += ${INCLUDES} ${GLIB_CFLAGS} ${GTK_CFLAGS} -I../.. -I. -I../audacious/platform ${platform_defines} -LIBS += ${GLIB_LIBS} ${GTK_LIBS} ${platform_libs} +LIBS += ${GLIB_LIBS} ${GTK_LIBS} ${ICE_LIBS} ${platform_libs} diff --git a/src/libguess/Makefile b/src/libguess/Makefile index a21558d..e2f6937 100644 --- a/src/libguess/Makefile +++ b/src/libguess/Makefile @@ -5,6 +5,7 @@ SRCS = guess.c \ greek_impl.c \ hebrew_impl.c \ russian_impl.c \ - turkish_impl.c + turkish_impl.c \ + polish_impl.c include ../../buildsys.mk diff --git a/src/libguess/guess.c b/src/libguess/guess.c index b7e2ef0..847972e 100644 --- a/src/libguess/guess.c +++ b/src/libguess/guess.c @@ -35,6 +35,7 @@ void guess_init(void) guess_impl_register(GUESS_REGION_TR, guess_tr); guess_impl_register(GUESS_REGION_GR, guess_gr); guess_impl_register(GUESS_REGION_HW, guess_hw); + guess_impl_register(GUESS_REGION_PL, guess_pl); } const char *guess_encoding(const char *inbuf, int buflen, const char *lang) diff --git a/src/libguess/libguess.h b/src/libguess/libguess.h index 4a634d0..1528f0a 100644 --- a/src/libguess/libguess.h +++ b/src/libguess/libguess.h @@ -51,6 +51,7 @@ const char *guess_ar(const char *buf, int buflen); const char *guess_tr(const char *buf, int buflen); const char *guess_gr(const char *buf, int buflen); const char *guess_hw(const char *buf, int buflen); +const char *guess_pl(const char *buf, int buflen); int dfa_validate_utf8(const char *buf, int buflen); #define GUESS_REGION_JP "japanese" @@ -62,6 +63,7 @@ int dfa_validate_utf8(const char *buf, int buflen); #define GUESS_REGION_TR "turkish" #define GUESS_REGION_GR "greek" #define GUESS_REGION_HW "hebrew" +#define GUESS_REGION_PL "polish" const char *guess_encoding(const char *buf, int buflen, const char *lang); void guess_init(void); diff --git a/src/libguess/polish_impl.c b/src/libguess/polish_impl.c new file mode 100644 index 0000000..b72cfcb --- /dev/null +++ b/src/libguess/polish_impl.c @@ -0,0 +1,53 @@ +/* + * Copyright 2010 Michał Lipski <tallica@o2.pl> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +static const char *_guess_pl(const unsigned char *ptr, int size) +{ + int i; + + for (i = 0; i < size; i++) + { + if (ptr[i] == 0xB9 || //ą + ptr[i] == 0xE6 || //ć + ptr[i] == 0xEA || //ę + ptr[i] == 0xB3 || //ł + ptr[i] == 0xF1 || //ń + ptr[i] == 0xF3 || //ó + ptr[i] == 0x9C || //ś + ptr[i] == 0x9F || //ź + ptr[i] == 0xBF || //ż + ptr[i] == 0xA5 || //Ą + ptr[i] == 0xC6 || //Ć + ptr[i] == 0xCA || //Ę + ptr[i] == 0xA3 || //Ł + ptr[i] == 0xD1 || //Ń + ptr[i] == 0xD3 || //Ó + ptr[i] == 0x8C || //Ś + ptr[i] == 0x8F || //Ź + ptr[i] == 0xAF) //Ż + + return "CP1250"; + } + + return "ISO-8859-2"; +} + +const char *guess_pl(const char *ptr, int size) +{ + return _guess_pl((const unsigned char *) ptr, size); +} diff --git a/src/libid3tag/Makefile b/src/libid3tag/Makefile deleted file mode 100644 index 1a49ef9..0000000 --- a/src/libid3tag/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -LIB = ${LIB_PREFIX}audid3tag${LIB_SUFFIX} -LIB_MAJOR = 2 -LIB_MINOR = 0 - -LIBDIR = ${plugindir} - -INCLUDES = id3tag.h - -SRCS = compat.c \ - debug.c \ - file.c \ - frametype.c \ - latin1.c \ - render.c \ - ucs4.c \ - utf8.c \ - version.c \ - crc.c \ - field.c \ - frame.c \ - genre.c \ - parse.c \ - tag.c \ - utf16.c \ - util.c - -include ../../buildsys.mk -include ../../extra.mk - -CPPFLAGS += ${LIB_CPPFLAGS} -I.. ${GLIB_CFLAGS} ${GTK_CFLAGS} \ - ${MOWGLI_CFLAGS} ${LIBMCS_CFLAGS} - -CFLAGS += ${LIB_CFLAGS} -LIBS += -lz ${GLIB_LIBS} diff --git a/src/libid3tag/README.audacious b/src/libid3tag/README.audacious deleted file mode 100644 index 4ea0ebe..0000000 --- a/src/libid3tag/README.audacious +++ /dev/null @@ -1,9 +0,0 @@ -The sources in libid3tag are heavily modified by the Audacious team for -use in Audacious. If you are a package maintainer, please do not patch -out this library as Audacious needs the modifications made here. - -The modifications are as follows: - - use the Audacious VFS subsystem for stream I/O instead of libc - - add support for opening an id3 tagged file from a live VFS handle. - - some minor portability improvements - diff --git a/src/libid3tag/compat.c b/src/libid3tag/compat.c deleted file mode 100644 index 0b22d7c..0000000 --- a/src/libid3tag/compat.c +++ /dev/null @@ -1,412 +0,0 @@ -/* C code produced by gperf version 2.7 */ -/* Command-line: gperf -tCcTonD -K id -N id3_compat_lookup -s -3 -k * compat.gperf */ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Id: compat.gperf,v 1.11 2004/01/23 09:41:32 rob Exp - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <stdlib.h> -# include <string.h> - -# ifdef HAVE_ASSERT_H -# include <assert.h> -# endif - -# include "id3tag.h" -# include "compat.h" -# include "frame.h" -# include "field.h" -# include "parse.h" -# include "ucs4.h" - -# define EQ(id) #id, 0 -# define OBSOLETE 0, 0 -# define TX(id) #id, translate_##id - -static id3_compat_func_t translate_TCON; - -#define TOTAL_KEYWORDS 73 -#define MIN_WORD_LENGTH 3 -#define MAX_WORD_LENGTH 4 -#define MIN_HASH_VALUE 1 -#define MAX_HASH_VALUE 84 -/* maximum key range = 84, duplicates = 10 */ - -#ifdef __GNUC__ -__inline -#endif -static unsigned int -hash (str, len) - register const char *str; - register unsigned int len; -{ - static const unsigned char asso_values[] = - { - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 22, - 21, 27, 26, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 9, 3, 0, 27, 16, - 6, 30, 85, 15, 85, 22, 2, 15, 4, 1, - 0, 30, 13, 17, 22, 0, 24, 5, 31, 25, - 15, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85 - }; - register int hval = 0; - - switch (len) - { - default: - case 4: - hval += asso_values[(unsigned char)str[3]]; - case 3: - hval += asso_values[(unsigned char)str[2]]; - case 2: - hval += asso_values[(unsigned char)str[1]]; - case 1: - hval += asso_values[(unsigned char)str[0]]; - break; - } - return hval; -} - -#ifdef __GNUC__ -__inline -#endif -const struct id3_compat * -id3_compat_lookup (str, len) - register const char *str; - register unsigned int len; -{ - static const struct id3_compat wordlist[] = - { - {"POP", EQ(POPM) /* Popularimeter */}, - {"WCP", EQ(WCOP) /* Copyright/legal information */}, - {"WPB", EQ(WPUB) /* Publishers official webpage */}, - {"BUF", EQ(RBUF) /* Recommended buffer size */}, - {"PIC", EQ(APIC) /* Attached picture */}, - {"COM", EQ(COMM) /* Comments */}, - {"IPL", EQ(TIPL) /* Involved people list */}, - {"MLL", EQ(MLLT) /* MPEG location lookup table */}, - {"WAF", EQ(WOAF) /* Official audio file webpage */}, - {"WCM", EQ(WCOM) /* Commercial information */}, - {"UFI", EQ(UFID) /* Unique file identifier */}, - {"CRA", EQ(AENC) /* Audio encryption */}, - {"TCO", TX(TCON) /* Content type */}, - {"ULT", EQ(USLT) /* Unsynchronised lyric/text transcription */}, - {"TOL", EQ(TOLY) /* Original lyricist(s)/text writer(s) */}, - {"TBP", EQ(TBPM) /* BPM (beats per minute) */}, - {"TPB", EQ(TPUB) /* Publisher */}, - {"CNT", EQ(PCNT) /* Play counter */}, - {"TCON", TX(TCON) /* Content type */}, - {"WAR", EQ(WOAR) /* Official artist/performer webpage */}, - {"LNK", EQ(LINK) /* Linked information */}, - {"CRM", OBSOLETE /* Encrypted meta frame [obsolete] */}, - {"TOF", EQ(TOFN) /* Original filename */}, - {"MCI", EQ(MCDI) /* Music CD identifier */}, - {"TPA", EQ(TPOS) /* Part of a set */}, - {"WAS", EQ(WOAS) /* Official audio source webpage */}, - {"TOA", EQ(TOPE) /* Original artist(s)/performer(s) */}, - {"TAL", EQ(TALB) /* Album/movie/show title */}, - {"TLA", EQ(TLAN) /* Language(s) */}, - {"IPLS", EQ(TIPL) /* Involved people list */}, - {"TCR", EQ(TCOP) /* Copyright message */}, - {"TRC", EQ(TSRC) /* ISRC (international standard recording code) */}, - {"TOR", EQ(TDOR) /* Original release year [obsolete] */}, - {"TCM", EQ(TCOM) /* Composer */}, - {"ETC", EQ(ETCO) /* Event timing codes */}, - {"STC", EQ(SYTC) /* Synchronised tempo codes */}, - {"TLE", EQ(TLEN) /* Length */}, - {"SLT", EQ(SYLT) /* Synchronised lyric/text */}, - {"TEN", EQ(TENC) /* Encoded by */}, - {"TP2", EQ(TPE2) /* Band/orchestra/accompaniment */}, - {"TP1", EQ(TPE1) /* Lead performer(s)/soloist(s) */}, - {"TOT", EQ(TOAL) /* Original album/movie/show title */}, - {"EQU", OBSOLETE /* Equalization [obsolete] */}, - {"RVA", OBSOLETE /* Relative volume adjustment [obsolete] */}, - {"GEO", EQ(GEOB) /* General encapsulated object */}, - {"TP4", EQ(TPE4) /* Interpreted, remixed, or otherwise modified by */}, - {"TP3", EQ(TPE3) /* Conductor/performer refinement */}, - {"TFT", EQ(TFLT) /* File type */}, - {"TIM", OBSOLETE /* Time [obsolete] */}, - {"REV", EQ(RVRB) /* Reverb */}, - {"TSI", OBSOLETE /* Size [obsolete] */}, - {"EQUA", OBSOLETE /* Equalization [obsolete] */}, - {"TSS", EQ(TSSE) /* Software/hardware and settings used for encoding */}, - {"TRK", EQ(TRCK) /* Track number/position in set */}, - {"TDA", OBSOLETE /* Date [obsolete] */}, - {"TMT", EQ(TMED) /* Media type */}, - {"TKE", EQ(TKEY) /* Initial key */}, - {"TORY", EQ(TDOR) /* Original release year [obsolete] */}, - {"TRD", OBSOLETE /* Recording dates [obsolete] */}, - {"TYE", OBSOLETE /* Year [obsolete] */}, - {"TT2", EQ(TIT2) /* Title/songname/content description */}, - {"TT1", EQ(TIT1) /* Content group description */}, - {"WXX", EQ(WXXX) /* User defined URL link frame */}, - {"TIME", OBSOLETE /* Time [obsolete] */}, - {"TSIZ", OBSOLETE /* Size [obsolete] */}, - {"TT3", EQ(TIT3) /* Subtitle/description refinement */}, - {"TRDA", OBSOLETE /* Recording dates [obsolete] */}, - {"RVAD", OBSOLETE /* Relative volume adjustment [obsolete] */}, - {"TDY", EQ(TDLY) /* Playlist delay */}, - {"TXT", EQ(TEXT) /* Lyricist/text writer */}, - {"TYER", OBSOLETE /* Year [obsolete] */}, - {"TDAT", OBSOLETE /* Date [obsolete] */}, - {"TXX", EQ(TXXX) /* User defined text information frame */} - }; - - static const short lookup[] = - { - -1, 0, -1, -53, -2, 1, -49, -2, - 2, 3, -1, -46, -2, -43, -2, 4, - 5, 6, -1, 7, -163, 10, 11, 12, - 13, -161, 17, -159, -77, 22, 23, -80, - 26, -85, 29, -87, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, -155, 44, - 45, 46, 47, -1, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, - -1, 60, 61, 62, 63, 64, -1, -151, - -1, 67, 68, 69, 70, -8, -2, -1, - 71, -31, -2, -1, 72, -55, -2, -59, - -3, -65, -2 - }; - - if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) - { - register int key = hash (str, len); - - if (key <= MAX_HASH_VALUE && key >= 0) - { - register int index = lookup[key]; - - if (index >= 0) - { - register const char *s = wordlist[index].id; - - if (*str == *s && !strncmp (str + 1, s + 1, len - 1)) - return &wordlist[index]; - } - else if (index < -TOTAL_KEYWORDS) - { - register int offset = - 1 - TOTAL_KEYWORDS - index; - register const struct id3_compat *wordptr = &wordlist[TOTAL_KEYWORDS + lookup[offset]]; - register const struct id3_compat *wordendptr = wordptr + -lookup[offset + 1]; - - while (wordptr < wordendptr) - { - register const char *s = wordptr->id; - - if (*str == *s && !strncmp (str + 1, s + 1, len - 1)) - return wordptr; - wordptr++; - } - } - } - } - return 0; -} - -static -int translate_TCON(struct id3_frame *frame, char const *oldid, - id3_byte_t const *data, id3_length_t length) -{ - id3_byte_t const *end; - enum id3_field_textencoding encoding; - id3_ucs4_t *string = 0, *ptr, *endptr; - int result = 0; - - /* translate old TCON syntax into multiple strings */ - - assert(frame->nfields == 2); - - encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1; - - end = data + length; - - if (id3_field_parse(&frame->fields[0], &data, end - data, &encoding) == -1) - goto fail; - - string = id3_parse_string(&data, end - data, encoding, 0); - if (string == 0) - goto fail; - - ptr = string; - while (*ptr == '(') { - if (*++ptr == '(') - break; - - endptr = ptr; - while (*endptr && *endptr != ')') - ++endptr; - - if (*endptr) - *endptr++ = 0; - - if (id3_field_addstring(&frame->fields[1], ptr) == -1) - goto fail; - - ptr = endptr; - } - - if (*ptr && id3_field_addstring(&frame->fields[1], ptr) == -1) - goto fail; - - if (0) { - fail: - result = -1; - } - - if (string) - free(string); - - return result; -} - -/* - * NAME: compat->fixup() - * DESCRIPTION: finish compatibility translations - */ -int id3_compat_fixup(struct id3_tag *tag) -{ - struct id3_frame *frame; - unsigned int index; - id3_ucs4_t timestamp[17] = { 0 }; - int result = 0; - - /* create a TDRC frame from obsolete TYER/TDAT/TIME frames */ - - /* - * TYE/TYER: YYYY - * TDA/TDAT: DDMM - * TIM/TIME: HHMM - * - * TDRC: yyyy-MM-ddTHH:mm - */ - - index = 0; - while ((frame = id3_tag_findframe(tag, ID3_FRAME_OBSOLETE, index++))) { - char const *id; - id3_byte_t const *data, *end; - id3_length_t length; - enum id3_field_textencoding encoding; - id3_ucs4_t *string; - - id = id3_field_getframeid(&frame->fields[0]); - assert(id); - - if (strcmp(id, "TYER") != 0 && strcmp(id, "YTYE") != 0 && - strcmp(id, "TDAT") != 0 && strcmp(id, "YTDA") != 0 && - strcmp(id, "TIME") != 0 && strcmp(id, "YTIM") != 0) - continue; - - data = id3_field_getbinarydata(&frame->fields[1], &length); - assert(data); - - if (length < 1) - continue; - - end = data + length; - - encoding = id3_parse_uint(&data, 1); - string = id3_parse_string(&data, end - data, encoding, 0); - - if (string == 0) - continue; - - if (id3_ucs4_length(string) < 4) { - free(string); - continue; - } - - if (strcmp(id, "TYER") == 0 || - strcmp(id, "YTYE") == 0) { - timestamp[0] = string[0]; - timestamp[1] = string[1]; - timestamp[2] = string[2]; - timestamp[3] = string[3]; - } - else if (strcmp(id, "TDAT") == 0 || - strcmp(id, "YTDA") == 0) { - timestamp[4] = '-'; - timestamp[5] = string[2]; - timestamp[6] = string[3]; - timestamp[7] = '-'; - timestamp[8] = string[0]; - timestamp[9] = string[1]; - } - else { /* TIME or YTIM */ - timestamp[10] = 'T'; - timestamp[11] = string[0]; - timestamp[12] = string[1]; - timestamp[13] = ':'; - timestamp[14] = string[2]; - timestamp[15] = string[3]; - } - - free(string); - } - - if (timestamp[0]) { - id3_ucs4_t *strings; - - frame = id3_frame_new("TDRC"); - if (frame == 0) - goto fail; - - strings = timestamp; - - if (id3_field_settextencoding(&frame->fields[0], - ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1 || - id3_field_setstrings(&frame->fields[1], 1, &strings) == -1 || - id3_tag_attachframe(tag, frame) == -1) { - id3_frame_delete(frame); - goto fail; - } - } - - if (0) { - fail: - result = -1; - } - - return result; -} diff --git a/src/libid3tag/compat.gperf b/src/libid3tag/compat.gperf deleted file mode 100644 index 8d33868..0000000 --- a/src/libid3tag/compat.gperf +++ /dev/null @@ -1,300 +0,0 @@ -%{ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: compat.gperf,v 1.11 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <stdlib.h> -# include <string.h> - -# ifdef HAVE_ASSERT_H -# include <assert.h> -# endif - -# include "id3tag.h" -# include "compat.h" -# include "frame.h" -# include "field.h" -# include "parse.h" -# include "ucs4.h" - -# define EQ(id) #id, 0 -# define OBSOLETE 0, 0 -# define TX(id) #id, translate_##id - -static id3_compat_func_t translate_TCON; -%} -struct id3_compat; -%% -# -# ID3v2.2 and ID3v2.3 frames -# -# Only obsolete frames or frames with an equivalent ID3v2.4 frame ID are -# listed here. If a frame ID is not listed, it is assumed that the same -# frame ID is itself the equivalent ID3v2.4 frame ID. -# -# This list may also include frames with new content interpretations; the -# translation function will rewrite the contents to comply with ID3v2.4. -# -BUF, EQ(RBUF) /* Recommended buffer size */ -CNT, EQ(PCNT) /* Play counter */ -COM, EQ(COMM) /* Comments */ -CRA, EQ(AENC) /* Audio encryption */ -CRM, OBSOLETE /* Encrypted meta frame [obsolete] */ -EQU, OBSOLETE /* Equalization [obsolete] */ -EQUA, OBSOLETE /* Equalization [obsolete] */ -ETC, EQ(ETCO) /* Event timing codes */ -GEO, EQ(GEOB) /* General encapsulated object */ -IPL, EQ(TIPL) /* Involved people list */ -IPLS, EQ(TIPL) /* Involved people list */ -LNK, EQ(LINK) /* Linked information */ -MCI, EQ(MCDI) /* Music CD identifier */ -MLL, EQ(MLLT) /* MPEG location lookup table */ -PIC, EQ(APIC) /* Attached picture */ -POP, EQ(POPM) /* Popularimeter */ -REV, EQ(RVRB) /* Reverb */ -RVA, OBSOLETE /* Relative volume adjustment [obsolete] */ -RVAD, OBSOLETE /* Relative volume adjustment [obsolete] */ -SLT, EQ(SYLT) /* Synchronised lyric/text */ -STC, EQ(SYTC) /* Synchronised tempo codes */ -TAL, EQ(TALB) /* Album/movie/show title */ -TBP, EQ(TBPM) /* BPM (beats per minute) */ -TCM, EQ(TCOM) /* Composer */ -TCO, TX(TCON) /* Content type */ -TCON, TX(TCON) /* Content type */ -TCR, EQ(TCOP) /* Copyright message */ -TDA, OBSOLETE /* Date [obsolete] */ -TDAT, OBSOLETE /* Date [obsolete] */ -TDY, EQ(TDLY) /* Playlist delay */ -TEN, EQ(TENC) /* Encoded by */ -TFT, EQ(TFLT) /* File type */ -TIM, OBSOLETE /* Time [obsolete] */ -TIME, OBSOLETE /* Time [obsolete] */ -TKE, EQ(TKEY) /* Initial key */ -TLA, EQ(TLAN) /* Language(s) */ -TLE, EQ(TLEN) /* Length */ -TMT, EQ(TMED) /* Media type */ -TOA, EQ(TOPE) /* Original artist(s)/performer(s) */ -TOF, EQ(TOFN) /* Original filename */ -TOL, EQ(TOLY) /* Original lyricist(s)/text writer(s) */ -TOR, EQ(TDOR) /* Original release year [obsolete] */ -TORY, EQ(TDOR) /* Original release year [obsolete] */ -TOT, EQ(TOAL) /* Original album/movie/show title */ -TP1, EQ(TPE1) /* Lead performer(s)/soloist(s) */ -TP2, EQ(TPE2) /* Band/orchestra/accompaniment */ -TP3, EQ(TPE3) /* Conductor/performer refinement */ -TP4, EQ(TPE4) /* Interpreted, remixed, or otherwise modified by */ -TPA, EQ(TPOS) /* Part of a set */ -TPB, EQ(TPUB) /* Publisher */ -TRC, EQ(TSRC) /* ISRC (international standard recording code) */ -TRD, OBSOLETE /* Recording dates [obsolete] */ -TRDA, OBSOLETE /* Recording dates [obsolete] */ -TRK, EQ(TRCK) /* Track number/position in set */ -TSI, OBSOLETE /* Size [obsolete] */ -TSIZ, OBSOLETE /* Size [obsolete] */ -TSS, EQ(TSSE) /* Software/hardware and settings used for encoding */ -TT1, EQ(TIT1) /* Content group description */ -TT2, EQ(TIT2) /* Title/songname/content description */ -TT3, EQ(TIT3) /* Subtitle/description refinement */ -TXT, EQ(TEXT) /* Lyricist/text writer */ -TXX, EQ(TXXX) /* User defined text information frame */ -TYE, OBSOLETE /* Year [obsolete] */ -TYER, OBSOLETE /* Year [obsolete] */ -UFI, EQ(UFID) /* Unique file identifier */ -ULT, EQ(USLT) /* Unsynchronised lyric/text transcription */ -WAF, EQ(WOAF) /* Official audio file webpage */ -WAR, EQ(WOAR) /* Official artist/performer webpage */ -WAS, EQ(WOAS) /* Official audio source webpage */ -WCM, EQ(WCOM) /* Commercial information */ -WCP, EQ(WCOP) /* Copyright/legal information */ -WPB, EQ(WPUB) /* Publishers official webpage */ -WXX, EQ(WXXX) /* User defined URL link frame */ -%% - -static -int translate_TCON(struct id3_frame *frame, char const *oldid, - id3_byte_t const *data, id3_length_t length) -{ - id3_byte_t const *end; - enum id3_field_textencoding encoding; - id3_ucs4_t *string = 0, *ptr, *endptr; - int result = 0; - - /* translate old TCON syntax into multiple strings */ - - assert(frame->nfields == 2); - - encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1; - - end = data + length; - - if (id3_field_parse(&frame->fields[0], &data, end - data, &encoding) == -1) - goto fail; - - string = id3_parse_string(&data, end - data, encoding, 0); - if (string == 0) - goto fail; - - ptr = string; - while (*ptr == '(') { - if (*++ptr == '(') - break; - - endptr = ptr; - while (*endptr && *endptr != ')') - ++endptr; - - if (*endptr) - *endptr++ = 0; - - if (id3_field_addstring(&frame->fields[1], ptr) == -1) - goto fail; - - ptr = endptr; - } - - if (*ptr && id3_field_addstring(&frame->fields[1], ptr) == -1) - goto fail; - - if (0) { - fail: - result = -1; - } - - if (string) - free(string); - - return result; -} - -/* - * NAME: compat->fixup() - * DESCRIPTION: finish compatibility translations - */ -int id3_compat_fixup(struct id3_tag *tag) -{ - struct id3_frame *frame; - unsigned int index; - id3_ucs4_t timestamp[17] = { 0 }; - int result = 0; - - /* create a TDRC frame from obsolete TYER/TDAT/TIME frames */ - - /* - * TYE/TYER: YYYY - * TDA/TDAT: DDMM - * TIM/TIME: HHMM - * - * TDRC: yyyy-MM-ddTHH:mm - */ - - index = 0; - while ((frame = id3_tag_findframe(tag, ID3_FRAME_OBSOLETE, index++))) { - char const *id; - id3_byte_t const *data, *end; - id3_length_t length; - enum id3_field_textencoding encoding; - id3_ucs4_t *string; - - id = id3_field_getframeid(&frame->fields[0]); - assert(id); - - if (strcmp(id, "TYER") != 0 && strcmp(id, "YTYE") != 0 && - strcmp(id, "TDAT") != 0 && strcmp(id, "YTDA") != 0 && - strcmp(id, "TIME") != 0 && strcmp(id, "YTIM") != 0) - continue; - - data = id3_field_getbinarydata(&frame->fields[1], &length); - assert(data); - - if (length < 1) - continue; - - end = data + length; - - encoding = id3_parse_uint(&data, 1); - string = id3_parse_string(&data, end - data, encoding, 0); - - if (string == 0) - continue; - - if (id3_ucs4_length(string) < 4) { - free(string); - continue; - } - - if (strcmp(id, "TYER") == 0 || - strcmp(id, "YTYE") == 0) { - timestamp[0] = string[0]; - timestamp[1] = string[1]; - timestamp[2] = string[2]; - timestamp[3] = string[3]; - } - else if (strcmp(id, "TDAT") == 0 || - strcmp(id, "YTDA") == 0) { - timestamp[4] = '-'; - timestamp[5] = string[2]; - timestamp[6] = string[3]; - timestamp[7] = '-'; - timestamp[8] = string[0]; - timestamp[9] = string[1]; - } - else { /* TIME or YTIM */ - timestamp[10] = 'T'; - timestamp[11] = string[0]; - timestamp[12] = string[1]; - timestamp[13] = ':'; - timestamp[14] = string[2]; - timestamp[15] = string[3]; - } - - free(string); - } - - if (timestamp[0]) { - id3_ucs4_t *strings; - - frame = id3_frame_new("TDRC"); - if (frame == 0) - goto fail; - - strings = timestamp; - - if (id3_field_settextencoding(&frame->fields[0], - ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1 || - id3_field_setstrings(&frame->fields[1], 1, &strings) == -1 || - id3_tag_attachframe(tag, frame) == -1) { - id3_frame_delete(frame); - goto fail; - } - } - - if (0) { - fail: - result = -1; - } - - return result; -} diff --git a/src/libid3tag/compat.h b/src/libid3tag/compat.h deleted file mode 100644 index 8af71ec..0000000 --- a/src/libid3tag/compat.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: compat.h,v 1.8 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_COMPAT_H -# define LIBID3TAG_COMPAT_H - -# include "id3tag.h" - -typedef int id3_compat_func_t(struct id3_frame *, char const *, - id3_byte_t const *, id3_length_t); - -struct id3_compat { - char const *id; - char const *equiv; - id3_compat_func_t *translate; -}; - -struct id3_compat const *id3_compat_lookup(register char const *, - register unsigned int); - -int id3_compat_fixup(struct id3_tag *); - -# endif diff --git a/src/libid3tag/config.h b/src/libid3tag/config.h deleted file mode 100644 index 769f2e6..0000000 --- a/src/libid3tag/config.h +++ /dev/null @@ -1,80 +0,0 @@ -/* config.h. Generated by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Define to enable diagnostic debugging support. */ -/* #undef DEBUG */ - -/* Define to 1 if you have the <assert.h> header file. */ -#define HAVE_ASSERT_H 1 - -/* Define to 1 if you have the <dlfcn.h> header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the `ftruncate' function. */ -#define HAVE_FTRUNCATE 1 - -/* Define to 1 if you have the <inttypes.h> header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the `z' library (-lz). */ -#define HAVE_LIBZ 1 - -/* Define to 1 if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the <stdint.h> header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the <strings.h> header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the <string.h> header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the <sys/stat.h> header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the <sys/types.h> header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the <unistd.h> header file. */ -#define HAVE_UNISTD_H 1 - -/* Define to disable debugging assertions. */ -/* #undef NDEBUG */ - -/* Name of package */ -#define PACKAGE "libid3tag" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "support@underbit.com" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "ID3 Tag" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "ID3 Tag 0.15.1b" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libid3tag" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "0.15.1b" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "0.15.1b" - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -/* #undef inline */ -#endif diff --git a/src/libid3tag/crc.c b/src/libid3tag/crc.c deleted file mode 100644 index 742a5d8..0000000 --- a/src/libid3tag/crc.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: crc.c,v 1.11 2004/02/17 02:04:10 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include "id3tag.h" -# include "crc.h" - -static -unsigned long const crc_table[256] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, - 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, - 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, - 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, - 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, - 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, - 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, - - 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, - 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, - 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, - 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, - 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, - 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, - - 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, - 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, - 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, - 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, - 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, - 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, - 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, - - 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, - 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, - 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, - 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, - 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, - 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, - - 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, - 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, - 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, - 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, - 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, - 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, - 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, - 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, - 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, - 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, - 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, - 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, - 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, - - 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, - 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, - 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, - 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, - 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, - 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, - - 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, - 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, - 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, - 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, - 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, - 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, - 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL -}; - -/* - * NAME: crc->compute() - * DESCRIPTION: calculate CRC-32 value (ISO 3309) - */ -unsigned long id3_crc_compute(id3_byte_t const *data, id3_length_t length) -{ - register unsigned long crc; - - for (crc = 0xffffffffL; length >= 8; length -= 8) { - crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - } - - switch (length) { - case 7: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - case 6: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - case 5: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - case 4: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - case 3: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - case 2: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - case 1: crc = crc_table[(crc ^ *data++) & 0xff] ^ (crc >> 8); - case 0: break; - } - - return crc ^ 0xffffffffL; -} diff --git a/src/libid3tag/crc.h b/src/libid3tag/crc.h deleted file mode 100644 index 89a5a39..0000000 --- a/src/libid3tag/crc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: crc.h,v 1.8 2004/02/17 02:04:10 rob Exp $ - */ - -# ifndef LIBID3TAG_CRC_H -# define LIBID3TAG_CRC_H - -# include "id3tag.h" - -unsigned long id3_crc_compute(id3_byte_t const *, id3_length_t); - -# endif diff --git a/src/libid3tag/debug.c b/src/libid3tag/debug.c deleted file mode 100644 index d91a2c5..0000000 --- a/src/libid3tag/debug.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: debug.c,v 1.8 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# undef malloc -# undef calloc -# undef realloc -# undef free - -# include <stdio.h> -# include <stdlib.h> -# include <string.h> - -# include "debug.h" - -# if defined(DEBUG) - -# define DEBUG_MAGIC 0xdeadbeefL - -struct debug { - char const *file; - unsigned int line; - size_t size; - struct debug *next; - struct debug *prev; - long int magic; -}; - -static struct debug *allocated; -static int registered; - -static -void check(void) -{ - struct debug *debug; - - for (debug = allocated; debug; debug = debug->next) { - if (debug->magic != DEBUG_MAGIC) { - fprintf(stderr, "memory corruption\n"); - break; - } - - fprintf(stderr, "%s:%u: leaked %lu bytes\n", - debug->file, debug->line, debug->size); - } -} - -void *id3_debug_malloc(size_t size, char const *file, unsigned int line) -{ - struct debug *debug; - - if (!registered) { - atexit(check); - registered = 1; - } - - if (size == 0) - fprintf(stderr, "%s:%u: malloc(0)\n", file, line); - - debug = malloc(sizeof(*debug) + size); - if (debug == 0) { - fprintf(stderr, "%s:%u: malloc(%lu) failed\n", file, line, size); - return 0; - } - - debug->magic = DEBUG_MAGIC; - - debug->file = file; - debug->line = line; - debug->size = size; - - debug->next = allocated; - debug->prev = 0; - - if (allocated) - allocated->prev = debug; - - allocated = debug; - - return ++debug; -} - -void *id3_debug_calloc(size_t nmemb, size_t size, - char const *file, unsigned int line) -{ - void *ptr; - - ptr = id3_debug_malloc(nmemb * size, file, line); - if (ptr) - memset(ptr, 0, nmemb * size); - - return ptr; -} - -void *id3_debug_realloc(void *ptr, size_t size, - char const *file, unsigned int line) -{ - struct debug *debug, *new; - - if (size == 0) { - id3_debug_free(ptr, file, line); - return 0; - } - - if (ptr == 0) - return id3_debug_malloc(size, file, line); - - debug = ptr; - --debug; - - if (debug->magic != DEBUG_MAGIC) { - fprintf(stderr, "%s:%u: realloc(%p, %lu) memory not allocated\n", - file, line, ptr, size); - return 0; - } - - new = realloc(debug, sizeof(*debug) + size); - if (new == 0) { - fprintf(stderr, "%s:%u: realloc(%p, %lu) failed\n", file, line, ptr, size); - return 0; - } - - if (allocated == debug) - allocated = new; - - debug = new; - - debug->file = file; - debug->line = line; - debug->size = size; - - if (debug->next) - debug->next->prev = debug; - if (debug->prev) - debug->prev->next = debug; - - return ++debug; -} - -void id3_debug_free(void *ptr, char const *file, unsigned int line) -{ - struct debug *debug; - - if (ptr == 0) { - fprintf(stderr, "%s:%u: free(0)\n", file, line); - return; - } - - debug = ptr; - --debug; - - if (debug->magic != DEBUG_MAGIC) { - fprintf(stderr, "%s:%u: free(%p) memory not allocated\n", file, line, ptr); - return; - } - - debug->magic = 0; - - if (debug->next) - debug->next->prev = debug->prev; - if (debug->prev) - debug->prev->next = debug->next; - - if (allocated == debug) - allocated = debug->next; - - free(debug); -} - -void *id3_debug_release(void *ptr, char const *file, unsigned int line) -{ - struct debug *debug; - - if (ptr == 0) - return 0; - - debug = ptr; - --debug; - - if (debug->magic != DEBUG_MAGIC) { - fprintf(stderr, "%s:%u: release(%p) memory not allocated\n", - file, line, ptr); - return ptr; - } - - if (debug->next) - debug->next->prev = debug->prev; - if (debug->prev) - debug->prev->next = debug->next; - - if (allocated == debug) - allocated = debug->next; - - memmove(debug, debug + 1, debug->size); - - return debug; -} - -# endif diff --git a/src/libid3tag/debug.h b/src/libid3tag/debug.h deleted file mode 100644 index a9b4ce0..0000000 --- a/src/libid3tag/debug.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: debug.h,v 1.8 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_DEBUG_H -# define LIBID3TAG_DEBUG_H - -# include <stdlib.h> - -void *id3_debug_malloc(size_t, char const *, unsigned int); -void *id3_debug_calloc(size_t, size_t, char const *, unsigned int); -void *id3_debug_realloc(void *, size_t, char const *, unsigned int); -void id3_debug_free(void *, char const *, unsigned int); - -void *id3_debug_release(void *, char const *, unsigned int); - -# endif diff --git a/src/libid3tag/field.c b/src/libid3tag/field.c deleted file mode 100644 index 6698b86..0000000 --- a/src/libid3tag/field.c +++ /dev/null @@ -1,906 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: field.c,v 1.16 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <stdlib.h> -# include <stdio.h> -# include <string.h> - -# ifdef HAVE_ASSERT_H -# include <assert.h> -# endif - -# include "id3tag.h" -# include "field.h" -# include "frame.h" -# include "render.h" -# include "ucs4.h" -# include "latin1.h" -# include "parse.h" - -/* - * NAME: field->init() - * DESCRIPTION: initialize a field to a default value for the given type - */ -void id3_field_init(union id3_field *field, enum id3_field_type type) -{ - assert(field); - - switch (field->type = type) { - case ID3_FIELD_TYPE_TEXTENCODING: - case ID3_FIELD_TYPE_INT8: - case ID3_FIELD_TYPE_INT16: - case ID3_FIELD_TYPE_INT24: - case ID3_FIELD_TYPE_INT32: - field->number.value = 0; - break; - - case ID3_FIELD_TYPE_LATIN1: - case ID3_FIELD_TYPE_LATIN1FULL: - field->latin1.ptr = 0; - break; - - case ID3_FIELD_TYPE_LATIN1LIST: - field->latin1list.nstrings = 0; - field->latin1list.strings = 0; - - case ID3_FIELD_TYPE_STRING: - case ID3_FIELD_TYPE_STRINGFULL: - field->string.ptr = 0; - break; - - case ID3_FIELD_TYPE_STRINGLIST: - field->stringlist.nstrings = 0; - field->stringlist.strings = 0; - break; - - case ID3_FIELD_TYPE_LANGUAGE: - g_strlcpy(field->immediate.value, "XXX", sizeof(field->immediate.value)); - break; - - case ID3_FIELD_TYPE_FRAMEID: - g_strlcpy(field->immediate.value, "XXXX", sizeof(field->immediate.value)); - break; - - case ID3_FIELD_TYPE_DATE: - memset(field->immediate.value, 0, sizeof(field->immediate.value)); - break; - - case ID3_FIELD_TYPE_INT32PLUS: - case ID3_FIELD_TYPE_BINARYDATA: - field->binary.data = 0; - field->binary.length = 0; - break; - } -} - -/* - * NAME: field->finish() - * DESCRIPTION: reset a field, deallocating memory if necessary - */ -void id3_field_finish(union id3_field *field) -{ - unsigned int i; - - assert(field); - - switch (field->type) { - case ID3_FIELD_TYPE_TEXTENCODING: - case ID3_FIELD_TYPE_INT8: - case ID3_FIELD_TYPE_INT16: - case ID3_FIELD_TYPE_INT24: - case ID3_FIELD_TYPE_INT32: - case ID3_FIELD_TYPE_LANGUAGE: - case ID3_FIELD_TYPE_FRAMEID: - case ID3_FIELD_TYPE_DATE: - break; - - case ID3_FIELD_TYPE_LATIN1: - case ID3_FIELD_TYPE_LATIN1FULL: - if (field->latin1.ptr) { - free(field->latin1.ptr); - field->latin1.ptr = NULL; - } - break; - - case ID3_FIELD_TYPE_LATIN1LIST: - if (field->latin1list.strings) { - for (i = 0; i < field->latin1list.nstrings; ++i) - free(field->latin1list.strings[i]); - - free(field->latin1list.strings); - field->latin1list.nstrings = 0; - field->latin1list.strings = NULL; - } - break; - - case ID3_FIELD_TYPE_STRING: - case ID3_FIELD_TYPE_STRINGFULL: - if (field->string.ptr) { - free(field->string.ptr); - field->string.ptr = NULL; - } - break; - - case ID3_FIELD_TYPE_STRINGLIST: - if (field->stringlist.strings) { - for (i = 0; i < field->stringlist.nstrings; ++i) - free(field->stringlist.strings[i]); - - free(field->stringlist.strings); - field->stringlist.nstrings = 0; - field->stringlist.strings = NULL; - } - break; - - case ID3_FIELD_TYPE_INT32PLUS: - case ID3_FIELD_TYPE_BINARYDATA: - if (field->binary.data) { - free(field->binary.data); - field->binary.data = NULL; - } - break; - } - - id3_field_init(field, field->type); -} - -/* - * NAME: field->type() - * DESCRIPTION: return the value type of a field - */ -enum id3_field_type id3_field_type(union id3_field const *field) -{ - assert(field); - - return field->type; -} - -/* - * NAME: field->parse() - * DESCRIPTION: parse a field value - */ -int id3_field_parse(union id3_field *field, id3_byte_t const **ptr, - id3_length_t length, enum id3_field_textencoding *encoding) -{ - assert(field); - - id3_field_finish(field); - - switch (field->type) { - case ID3_FIELD_TYPE_INT32: - if (length < 4) - goto fail; - - field->number.value = id3_parse_uint(ptr, 4); - break; - - case ID3_FIELD_TYPE_INT24: - if (length < 3) - goto fail; - - field->number.value = id3_parse_uint(ptr, 3); - break; - - case ID3_FIELD_TYPE_INT16: - if (length < 2) - goto fail; - - field->number.value = id3_parse_uint(ptr, 2); - break; - - case ID3_FIELD_TYPE_INT8: - case ID3_FIELD_TYPE_TEXTENCODING: - if (length < 1) - goto fail; - - field->number.value = id3_parse_uint(ptr, 1); - - if (field->type == ID3_FIELD_TYPE_TEXTENCODING) - *encoding = field->number.value; - break; - - case ID3_FIELD_TYPE_LANGUAGE: - if (length < 3) - goto fail; - - id3_parse_immediate(ptr, 3, field->immediate.value); - break; - - case ID3_FIELD_TYPE_FRAMEID: - if (length < 4) - goto fail; - - id3_parse_immediate(ptr, 4, field->immediate.value); - break; - - case ID3_FIELD_TYPE_DATE: - if (length < 8) - goto fail; - - id3_parse_immediate(ptr, 8, field->immediate.value); - break; - - case ID3_FIELD_TYPE_LATIN1: - case ID3_FIELD_TYPE_LATIN1FULL: - { - id3_latin1_t *latin1; - - latin1 = id3_parse_latin1(ptr, length, - field->type == ID3_FIELD_TYPE_LATIN1FULL); - if (latin1 == 0) - goto fail; - - field->latin1.ptr = latin1; - } - break; - - case ID3_FIELD_TYPE_LATIN1LIST: - { - id3_byte_t const *end; - id3_latin1_t *latin1, **strings; - - end = *ptr + length; - - while (end - *ptr > 0 && **ptr != '\0') { - latin1 = id3_parse_latin1(ptr, end - *ptr, 0); - if (latin1 == 0) - goto fail; - - strings = realloc(field->latin1list.strings, - (field->latin1list.nstrings + 1) * sizeof(*strings)); - if (strings == 0) { - free(latin1); - goto fail; - } - - field->latin1list.strings = strings; - field->latin1list.strings[field->latin1list.nstrings++] = latin1; - } - } - break; - - case ID3_FIELD_TYPE_STRING: - case ID3_FIELD_TYPE_STRINGFULL: - { - id3_ucs4_t *ucs4; - - ucs4 = id3_parse_string(ptr, length, *encoding, - field->type == ID3_FIELD_TYPE_STRINGFULL); - if (ucs4 == 0) - goto fail; - - field->string.ptr = ucs4; - } - break; - - case ID3_FIELD_TYPE_STRINGLIST: - { - id3_byte_t const *end; - id3_ucs4_t *ucs4, **strings; - - end = *ptr + length; - - while (end - *ptr > 0 && **ptr != '\0') { - ucs4 = id3_parse_string(ptr, end - *ptr, *encoding, 0); - if (ucs4 == 0) - goto fail; - - strings = realloc(field->stringlist.strings, - (field->stringlist.nstrings + 1) * sizeof(*strings)); - if (strings == 0) { - free(ucs4); - goto fail; - } - - field->stringlist.strings = strings; - field->stringlist.strings[field->stringlist.nstrings++] = ucs4; - } - } - break; - - case ID3_FIELD_TYPE_INT32PLUS: - case ID3_FIELD_TYPE_BINARYDATA: - { - id3_byte_t *data; - - data = id3_parse_binary(ptr, length); - if (data == 0) - goto fail; - - field->binary.data = data; - field->binary.length = length; - } - break; - } - - return 0; - - fail: - return -1; -} - -/* - * NAME: field->render() - * DESCRIPTION: render a field value - */ -id3_length_t id3_field_render(union id3_field const *field, id3_byte_t **ptr, - enum id3_field_textencoding *encoding, - int terminate) -{ - id3_length_t size; - unsigned int i; - - assert(field && encoding); - - switch (field->type) { - case ID3_FIELD_TYPE_INT32: - return id3_render_int(ptr, field->number.value, 4); - - case ID3_FIELD_TYPE_INT24: - return id3_render_int(ptr, field->number.value, 3); - - case ID3_FIELD_TYPE_INT16: - return id3_render_int(ptr, field->number.value, 2); - - case ID3_FIELD_TYPE_TEXTENCODING: - *encoding = field->number.value; - case ID3_FIELD_TYPE_INT8: - return id3_render_int(ptr, field->number.value, 1); - - case ID3_FIELD_TYPE_LATIN1: - case ID3_FIELD_TYPE_LATIN1FULL: - return id3_render_latin1(ptr, field->latin1.ptr, terminate); - - case ID3_FIELD_TYPE_LATIN1LIST: - size = 0; - for (i = 0; i < field->latin1list.nstrings; ++i) { - size += id3_render_latin1(ptr, field->latin1list.strings[i], - (i < field->latin1list.nstrings - 1) || - terminate); - } - return size; - - case ID3_FIELD_TYPE_STRING: - case ID3_FIELD_TYPE_STRINGFULL: // here !! --yaz - return id3_render_string(ptr, field->string.ptr, *encoding, terminate); - - case ID3_FIELD_TYPE_STRINGLIST: - size = 0; - for (i = 0; i < field->stringlist.nstrings; ++i) { - size += id3_render_string(ptr, field->stringlist.strings[i], *encoding, - (i < field->stringlist.nstrings - 1) || - terminate); - } - return size; - - case ID3_FIELD_TYPE_LANGUAGE: - return id3_render_immediate(ptr, field->immediate.value, 3); - - case ID3_FIELD_TYPE_FRAMEID: - return id3_render_immediate(ptr, field->immediate.value, 4); - - case ID3_FIELD_TYPE_DATE: - return id3_render_immediate(ptr, field->immediate.value, 8); - - case ID3_FIELD_TYPE_INT32PLUS: - case ID3_FIELD_TYPE_BINARYDATA: - return id3_render_binary(ptr, field->binary.data, field->binary.length); - } - - return 0; -} - -/* - * NAME: field->setint() - * DESCRIPTION: set the value of an int field - */ -int id3_field_setint(union id3_field *field, signed long number) -{ - assert(field); - - switch (field->type) { - case ID3_FIELD_TYPE_INT8: - if (number > 0x7f || number < -0x80) - return -1; - break; - - case ID3_FIELD_TYPE_INT16: - if (number > 0x7fff || number < -0x8000) - return -1; - break; - - case ID3_FIELD_TYPE_INT24: - if (number > 0x7fffffL || number < -0x800000L) - return -1; - break; - - case ID3_FIELD_TYPE_INT32: - if (number > 0x7fffffffL || number < -0x80000000L) - return -1; - break; - - default: - return -1; - } - - id3_field_finish(field); - - field->number.value = number; - - return 0; -} - -/* - * NAME: field->settextencoding() - * DESCRIPTION: set the value of a textencoding field - */ -int id3_field_settextencoding(union id3_field *field, - enum id3_field_textencoding encoding) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_TEXTENCODING) { - return -1; - } - - id3_field_finish(field); - - field->number.value = encoding; - - return 0; -} - -static -int set_latin1(union id3_field *field, id3_latin1_t const *latin1) -{ - id3_latin1_t *data; - - if (latin1 == 0 || *latin1 == 0) - data = 0; - else { - data = id3_latin1_duplicate(latin1); - if (data == 0) - return -1; - } - - field->latin1.ptr = data; - - return 0; -} - -/* - * NAME: field->setlatin1() - * DESCRIPTION: set the value of a latin1 field - */ -int id3_field_setlatin1(union id3_field *field, id3_latin1_t const *latin1) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_LATIN1) - return -1; - - id3_field_finish(field); - - if (latin1) { - id3_latin1_t const *ptr; - - for (ptr = latin1; *ptr; ++ptr) { - if (*ptr == '\n') - return -1; - } - } - - return set_latin1(field, latin1); -} - -/* - * NAME: field->setfulllatin1() - * DESCRIPTION: set the value of a full latin1 field - */ -int id3_field_setfulllatin1(union id3_field *field, id3_latin1_t const *latin1) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_LATIN1FULL) - return -1; - - id3_field_finish(field); - - return set_latin1(field, latin1); -} - -static -int set_string(union id3_field *field, id3_ucs4_t const *string) -{ - id3_ucs4_t *data; - - if (string == 0 || *string == 0) - data = 0; - else { - data = id3_ucs4_duplicate(string); - if (data == 0) - return -1; - } - - field->string.ptr = data; - - return 0; -} - -/* - * NAME: field->setstring() - * DESCRIPTION: set the value of a string field - */ -int id3_field_setstring(union id3_field *field, id3_ucs4_t const *string) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_STRING) - return -1; - - id3_field_finish(field); - - if (string) { - id3_ucs4_t const *ptr; - - for (ptr = string; *ptr; ++ptr) { - if (*ptr == '\n') - return -1; - } - } - - return set_string(field, string); -} - -/* - * NAME: field->setfullstring() - * DESCRIPTION: set the value of a full string field - */ -int id3_field_setfullstring(union id3_field *field, id3_ucs4_t const *string) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_STRINGFULL) - return -1; - - id3_field_finish(field); - - return set_string(field, string); -} - -/* - * NAME: field->setstrings() - * DESCRIPTION: set the value of a stringlist field - */ -int id3_field_setstrings(union id3_field *field, - unsigned int length, id3_ucs4_t **ptrs) -{ - id3_ucs4_t **strings; - unsigned int i; - - assert(field); - - if (field->type != ID3_FIELD_TYPE_STRINGLIST) - return -1; - - id3_field_finish(field); - - if (length == 0) - return 0; - - strings = malloc(length * sizeof(*strings)); - if (strings == 0) - return -1; - - for (i = 0; i < length; ++i) { - strings[i] = id3_ucs4_duplicate(ptrs[i]); - if (strings[i] == 0) { - while (i--) - free(strings[i]); - - free(strings); - return -1; - } - } - - field->stringlist.strings = strings; - field->stringlist.nstrings = length; - - return 0; -} - -/* - * NAME: field->addstring() - * DESCRIPTION: add a string to a stringlist field - */ -int id3_field_addstring(union id3_field *field, id3_ucs4_t const *string) -{ - id3_ucs4_t *new, **strings; - - assert(field); - - if (field->type != ID3_FIELD_TYPE_STRINGLIST) - return -1; - - if (string == 0) - string = id3_ucs4_empty; - - new = id3_ucs4_duplicate(string); - if (new == 0) - return -1; - - strings = realloc(field->stringlist.strings, - (field->stringlist.nstrings + 1) * sizeof(*strings)); - if (strings == 0) { - free(new); - return -1; - } - - field->stringlist.strings = strings; - field->stringlist.strings[field->stringlist.nstrings++] = new; - - return 0; -} - -/* - * NAME: field->setlanguage() - * DESCRIPTION: set the value of a language field - */ -int id3_field_setlanguage(union id3_field *field, char const *language) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_LANGUAGE) - return -1; - - id3_field_finish(field); - - if (language) { - if (strlen(language) != 3) - return -1; - - g_strlcpy(field->immediate.value, language, sizeof(field->immediate.value)); - } - - return 0; -} - -/* - * NAME: field->setframeid() - * DESCRIPTION: set the value of a frameid field - */ -int id3_field_setframeid(union id3_field *field, char const *id) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_FRAMEID || - !id3_frame_validid(id)) - return -1; - - id3_field_finish(field); - - field->immediate.value[0] = id[0]; - field->immediate.value[1] = id[1]; - field->immediate.value[2] = id[2]; - field->immediate.value[3] = id[3]; - field->immediate.value[4] = 0; - - return 0; -} - -/* - * NAME: field->setbinarydata() - * DESCRIPTION: set the value of a binarydata field - */ -int id3_field_setbinarydata(union id3_field *field, - id3_byte_t const *data, id3_length_t length) -{ - id3_byte_t *mem; - - assert(field); - - if (field->type != ID3_FIELD_TYPE_BINARYDATA) - return -1; - - id3_field_finish(field); - - if (length == 0) - mem = 0; - else { - mem = malloc(length); - if (mem == 0) - return -1; - - assert(data); - - memcpy(mem, data, length); - } - - field->binary.data = mem; - field->binary.length = length; - - return 0; -} - -/* - * NAME: field->getint() - * DESCRIPTION: return the value of an integer field - */ -signed long id3_field_getint(union id3_field const *field) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_INT8 && - field->type != ID3_FIELD_TYPE_INT16 && - field->type != ID3_FIELD_TYPE_INT24 && - field->type != ID3_FIELD_TYPE_INT32) - return -1; - - return field->number.value; -} - -/* - * NAME: field->gettextencoding() - * DESCRIPTION: return the value of a text encoding field - */ -enum id3_field_textencoding -id3_field_gettextencoding(union id3_field const *field) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_TEXTENCODING) - return -1; - - return field->number.value; -} - -/* - * NAME: field->getlatin1() - * DESCRIPTION: return the value of a latin1 field - */ -id3_latin1_t const *id3_field_getlatin1(union id3_field const *field) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_LATIN1) - return 0; - - return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) ""; -} - -/* - * NAME: field->getfulllatin1() - * DESCRIPTION: return the value of a full latin1 field - */ -id3_latin1_t const *id3_field_getfulllatin1(union id3_field const *field) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_LATIN1FULL) - return 0; - - return field->latin1.ptr ? field->latin1.ptr : (id3_latin1_t const *) ""; -} - -/* - * NAME: field->getstring() - * DESCRIPTION: return the value of a string field - */ -id3_ucs4_t const *id3_field_getstring(union id3_field const *field) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_STRING) - return 0; - - return field->string.ptr ? field->string.ptr : id3_ucs4_empty; -} - -/* - * NAME: field->getfullstring() - * DESCRIPTION: return the value of a fullstring field - */ -id3_ucs4_t const *id3_field_getfullstring(union id3_field const *field) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_STRINGFULL) { - printf("not stringfull\n"); - return 0; - } - - return field->string.ptr ? field->string.ptr : id3_ucs4_empty; -} - -/* - * NAME: field->getnstrings() - * DESCRIPTION: return the number of strings in a stringlist field - */ -unsigned int id3_field_getnstrings(union id3_field const *field) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_STRINGLIST) - return 0; - - return field->stringlist.nstrings; -} - -/* - * NAME: field->getstrings() - * DESCRIPTION: return one value of a stringlist field - */ -id3_ucs4_t const *id3_field_getstrings(union id3_field const *field, - unsigned int index) -{ - id3_ucs4_t const *string; - - assert(field); - - if (field->type != ID3_FIELD_TYPE_STRINGLIST || - index >= field->stringlist.nstrings) - return 0; - - string = field->stringlist.strings[index]; - - return string ? string : id3_ucs4_empty; -} - -/* - * NAME: field->getframeid() - * DESCRIPTION: return the value of a frameid field - */ -char const *id3_field_getframeid(union id3_field const *field) -{ - assert(field); - - if (field->type != ID3_FIELD_TYPE_FRAMEID) - return 0; - - return field->immediate.value; -} - -/* - * NAME: field->getbinarydata() - * DESCRIPTION: return the value of a binarydata field - */ -id3_byte_t const *id3_field_getbinarydata(union id3_field const *field, - id3_length_t *length) -{ - static id3_byte_t const empty; - - assert(field && length); - - if (field->type != ID3_FIELD_TYPE_BINARYDATA) - return 0; - - assert(field->binary.length == 0 || field->binary.data); - - *length = field->binary.length; - - return field->binary.data ? field->binary.data : ∅ -} diff --git a/src/libid3tag/field.h b/src/libid3tag/field.h deleted file mode 100644 index 2cf42b9..0000000 --- a/src/libid3tag/field.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: field.h,v 1.9 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_FIELD_H -# define LIBID3TAG_FIELD_H - -# include "id3tag.h" - -void id3_field_init(union id3_field *, enum id3_field_type); -void id3_field_finish(union id3_field *); - -int id3_field_parse(union id3_field *, id3_byte_t const **, - id3_length_t, enum id3_field_textencoding *); - -id3_length_t id3_field_render(union id3_field const *, id3_byte_t **, - enum id3_field_textencoding *, int); - -# endif diff --git a/src/libid3tag/file.c b/src/libid3tag/file.c deleted file mode 100644 index 082645e..0000000 --- a/src/libid3tag/file.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: file.c,v 1.21 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <stdio.h> -# include <stdlib.h> -# include <string.h> - -# ifdef HAVE_UNISTD_H -# include <unistd.h> -# endif - -# ifdef HAVE_ASSERT_H -# include <assert.h> -# endif - -# include "id3tag.h" -# include "file.h" -# include "tag.h" -# include "field.h" - -#define AUDACIOUS 1 -//#undef AUDACIOUS - -#ifdef AUDACIOUS - #include <libaudcore/vfs.h> -#else - #define VFSFile FILE - #define vfs_fopen fopen - #define vfs_fclose fclose - #define vfs_fseek fseek - #define vfs_ftell ftell - #define vfs_rewind rewind - #define vfs_fread fread - #define vfs_fwrite fwrite - #define vfs_truncate(x, y) ftruncate((fileno(x)), (y)) -#endif - -struct filetag { - struct id3_tag *tag; - unsigned long location; - id3_length_t length; -}; - -struct id3_file { - VFSFile *iofile; - enum id3_file_mode mode; - char *path; - - int flags; - - struct id3_tag *primary; - - unsigned int ntags; - struct filetag *tags; -}; - -enum { - ID3_FILE_FLAG_ID3V1 = 0x0001 -}; - -/* - * NAME: query_tag() - * DESCRIPTION: check for a tag at a file's current position - */ -static -signed long query_tag(VFSFile *iofile) -{ - int save_position; - id3_byte_t query[ID3_TAG_QUERYSIZE]; - signed long size; - - save_position = vfs_ftell(iofile); - if (save_position == -1) - return 0; - - size = id3_tag_query(query, vfs_fread(query, 1, sizeof(query), iofile)); - - if(vfs_fseek(iofile, save_position, SEEK_SET) == -1) - return 0; - - return size; -} - -/* - * NAME: read_tag() - * DESCRIPTION: read and parse a tag at a file's current position - */ -static -struct id3_tag *read_tag(VFSFile *iofile, id3_length_t size) -{ - id3_byte_t *data; - struct id3_tag *tag = 0; - - data = malloc(size); - if (data) { - if (vfs_fread(data, size, 1, iofile) == 1) - tag = id3_tag_parse(data, size); - - free(data); - } - - return tag; -} - -/* - * NAME: update_primary() - * DESCRIPTION: update the primary tag with data from a new tag - */ -static -int update_primary(struct id3_tag *tag, struct id3_tag const *new) -{ - unsigned int i; - struct id3_frame *frame; - - if (new) { - if (!(new->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE)) - id3_tag_clearframes(tag); - - i = 0; - while ((frame = id3_tag_findframe(new, 0, i++))) { - if (id3_tag_attachframe(tag, frame) == -1) - return -1; - } - } - - return 0; -} - -/* - * NAME: tag_compare() - * DESCRIPTION: tag sort function for qsort() - */ -static -int tag_compare(const void *a, const void *b) -{ - struct filetag const *tag1 = a, *tag2 = b; - - if (tag1->location < tag2->location) - return -1; - else if (tag1->location > tag2->location) - return +1; - - return 0; -} - -/* - * NAME: add_filetag() - * DESCRIPTION: add a new file tag entry - */ -static -int add_filetag(struct id3_file *file, struct filetag const *filetag) -{ - struct filetag *tags; - - tags = realloc(file->tags, (file->ntags + 1) * sizeof(*tags)); - if (tags == 0) - return -1; - - file->tags = tags; - file->tags[file->ntags++] = *filetag; - - /* sort tags by location */ - - if (file->ntags > 1) - qsort(file->tags, file->ntags, sizeof(file->tags[0]), tag_compare); - - return 0; -} - -/* - * NAME: del_filetag() - * DESCRIPTION: delete a file tag entry - */ -/* -static -void del_filetag(struct id3_file *file, unsigned int index) -{ - assert(index < file->ntags); - - while (index < file->ntags - 1) { - file->tags[index] = file->tags[index + 1]; - ++index; - } - - --file->ntags; -} -*/ - -/* - * NAME: add_tag() - * DESCRIPTION: read, parse, and add a tag to a file structure - */ -static -struct id3_tag *add_tag(struct id3_file *file, id3_length_t length) -{ - long location; - unsigned int i; - struct filetag filetag; - struct id3_tag *tag; - - location = vfs_ftell(file->iofile); - if (location == -1) - return 0; - - /* check for duplication/overlap */ - { - unsigned long begin1, end1, begin2, end2; - - begin1 = location; - end1 = begin1 + length; - - for (i = 0; i < file->ntags; ++i) { - begin2 = file->tags[i].location; - end2 = begin2 + file->tags[i].length; - - if (begin1 == begin2 && end1 == end2) - return file->tags[i].tag; /* duplicate */ - - if (begin1 < end2 && end1 > begin2) - return 0; /* overlap */ - } - } - - tag = read_tag(file->iofile, length); - - filetag.tag = tag; - filetag.location = location; - filetag.length = length; - - if (add_filetag(file, &filetag) == -1 || - update_primary(file->primary, tag) == -1) { - if (tag) - id3_tag_delete(tag); - return 0; - } - - if (tag) - id3_tag_addref(tag); - - return tag; -} - -/* - * NAME: search_tags() - * DESCRIPTION: search for tags in a file - */ -//static -int search_tags(struct id3_file *file) -{ - int save_position; - signed long size; - - /* - * save the current seek position - * - * We also verify the stream is seekable by calling fsetpos(), since - * fgetpos() alone is not reliable enough for this purpose. - * - * [Apparently not even fsetpos() is sufficient under Win32.] - */ - -// if (fgetpos(file->iofile, &save_position) == -1 || -// fsetpos(file->iofile, &save_position) == -1) -// if (save_position = vfs_ftell(file->iofile) == -1 || -// vfs_fseek(file->iofile, save_position, SEEK_SET) == -1) - if((save_position = vfs_ftell(file->iofile)) == -1) - return -1; - - /* look for an ID3v1 tag */ - - if (vfs_fseek(file->iofile, -128, SEEK_END) == 0) { - size = query_tag(file->iofile); - if (size > 0) { - struct id3_tag const *tag; - - tag = add_tag(file, size); - - /* if this is indeed an ID3v1 tag, mark the file so */ - - if (tag && (ID3_TAG_VERSION_MAJOR(id3_tag_version(tag)) == 1)) - file->flags |= ID3_FILE_FLAG_ID3V1; - } - } - - /* look for a tag at the beginning of the file */ - - vfs_rewind(file->iofile); - - size = query_tag(file->iofile); - if (size > 0) { - struct id3_tag const *tag; - struct id3_frame const *frame; - - tag = add_tag(file, size); - - /* locate tags indicated by SEEK frames */ - - while (tag && (frame = id3_tag_findframe(tag, "SEEK", 0))) { - long seek; - - seek = id3_field_getint(id3_frame_field(frame, 0)); - if (seek < 0 || vfs_fseek(file->iofile, seek, SEEK_CUR) == -1) - break; - - size = query_tag(file->iofile); - tag = (size > 0) ? add_tag(file, size) : 0; - } - } - - /* look for a tag at the end of the file (before any ID3v1 tag) */ - - if (vfs_fseek(file->iofile, ((file->flags & ID3_FILE_FLAG_ID3V1) ? -128 : 0) + - -10, SEEK_END) == 0) { - size = query_tag(file->iofile); - if (size < 0 && vfs_fseek(file->iofile, size, SEEK_CUR) == 0) { - size = query_tag(file->iofile); - if (size > 0) - add_tag(file, size); - } - } - -#ifndef AUDACIOUS - clearerr(file->iofile); -#endif - - /* restore seek position */ - - if (vfs_fseek(file->iofile, save_position, SEEK_SET) == -1) - return -1; - - /* set primary tag options and target padded length for convenience */ - - if ((file->ntags > 0 && !(file->flags & ID3_FILE_FLAG_ID3V1)) || - (file->ntags > 1 && (file->flags & ID3_FILE_FLAG_ID3V1))) { - if (file->tags[0].location == 0) - id3_tag_setlength(file->primary, file->tags[0].length); - else - id3_tag_options(file->primary, ID3_TAG_OPTION_APPENDEDTAG, ~0); - } - - return 0; -} - -/* - * NAME: finish_file() - * DESCRIPTION: release memory associated with a file - */ -static -void finish_file(struct id3_file *file) -{ - unsigned int i; - - if (file->path) - free(file->path); - - if (file->primary) { - id3_tag_delref(file->primary); - id3_tag_delete(file->primary); - } - - for (i = 0; i < file->ntags; ++i) { - struct id3_tag *tag; - - tag = file->tags[i].tag; - if (tag) { - id3_tag_delref(tag); - id3_tag_delete(tag); - } - } - - if (file->tags) - free(file->tags); - - free(file); -} - -/* - * NAME: new_file() - * DESCRIPTION: create a new file structure and load tags - */ -static -struct id3_file *new_file(VFSFile *iofile, enum id3_file_mode mode, - char const *path) -{ - struct id3_file *file; - - file = malloc(sizeof(*file)); - if (file == 0) - goto fail; - - file->iofile = iofile; - file->mode = mode; - file->path = path ? strdup(path) : 0; - - file->flags = 0; - - file->ntags = 0; - file->tags = 0; - - file->primary = id3_tag_new(); - if (file->primary == 0) - goto fail; - - id3_tag_addref(file->primary); - - /* load tags from the file */ - - if (search_tags(file) == -1) - goto fail; - - id3_tag_options(file->primary, ID3_TAG_OPTION_ID3V1, - (file->flags & ID3_FILE_FLAG_ID3V1) ? ~0 : 0); - - if (0) { - fail: - if (file) { - finish_file(file); - file = 0; - } - } - - return file; -} - - -/* - * NAME: file->open() - * DESCRIPTION: open a file given its pathname - */ -struct id3_file *id3_file_open(char const *path, enum id3_file_mode mode) -{ - VFSFile *iofile; - struct id3_file *file; - - assert(path); - - iofile = vfs_fopen(path, (mode == ID3_FILE_MODE_READWRITE) ? "r+b" : "rb"); - if (iofile == 0){ - printf("id3_file_open: iofile failed\n"); - return 0; - } - file = new_file(iofile, mode, path); - if (file == 0){ - printf("id3_file_open: file failed\n"); - vfs_fclose(iofile); - } - - return file; -} - -/* - * NAME: file->vfsopen() - * DESCRIPTION: open a file given its vfs - */ -struct id3_file *id3_file_vfsopen(VFSFile *iofile, enum id3_file_mode mode) -{ - struct id3_file *file; - glong curpos; - gchar *path; - - assert(iofile); - - path = iofile->uri; - - vfs_dup(iofile); - - curpos = vfs_ftell(iofile); - vfs_fseek(iofile, 0, SEEK_SET); - - file = new_file(iofile, mode, path); - if (file == 0){ - printf("id3_file_vfsopen: file failed\n"); - vfs_fclose(iofile); - } - - vfs_fseek(iofile, curpos, SEEK_SET); - - return file; -} - -/* - * NAME: file->fdopen() - * DESCRIPTION: open a file using an existing file descriptor - */ -#ifndef AUDACIOUS -struct id3_file *id3_file_fdopen(int fd, enum id3_file_mode mode) -{ -# if 1 || defined(HAVE_UNISTD_H) - VFSFile *iofile; - struct id3_file *file; - - iofile = fdopen(fd, (mode == ID3_FILE_MODE_READWRITE) ? "r+b" : "rb"); - if (iofile == 0) - return 0; - - file = new_file(iofile, mode, 0); - if (file == 0) { - int save_fd; - - /* close iofile without closing fd */ - - save_fd = dup(fd); - - fclose(iofile); - - dup2(save_fd, fd); - close(save_fd); - } - - return file; -# else - return 0; -# endif -} -#endif - -/* - * NAME: file->close() - * DESCRIPTION: close a file and delete its associated tags - */ -int id3_file_close(struct id3_file *file) -{ - int result = 0; - - assert(file); - - if (vfs_fclose(file->iofile) == EOF) - result = -1; - - finish_file(file); - - return result; -} - -/* - * NAME: file->tag() - * DESCRIPTION: return the primary tag structure for a file - */ -struct id3_tag *id3_file_tag(struct id3_file const *file) -{ - assert(file); - - return file->primary; -} - -/* - * NAME: v1_write() - * DESCRIPTION: write ID3v1 tag modifications to a file - */ -static -int v1_write(struct id3_file *file, - id3_byte_t const *data, id3_length_t length) -{ -// assert(!data || length == 128); - - if (data) { - long location; - - if (vfs_fseek(file->iofile, (file->flags & ID3_FILE_FLAG_ID3V1) ? -128 : 0, - SEEK_END) == -1 || - (location = vfs_ftell(file->iofile)) == -1 || -#ifdef AUDACIOUS - vfs_fwrite(data, 128, 1, file->iofile) != 1 ) -#else - vfs_fwrite(data, 128, 1, file->iofile) != 1 || - fflush(file->iofile) == EOF) //XXX -#endif - return -1; - - /* add file tag reference */ - - if (!(file->flags & ID3_FILE_FLAG_ID3V1)) { - struct filetag filetag; - - filetag.tag = 0; - filetag.location = location; - filetag.length = 128; - - if (add_filetag(file, &filetag) == -1) - return -1; - - file->flags |= ID3_FILE_FLAG_ID3V1; - } - } -# if defined(HAVE_FTRUNCATE) - else if (file->flags & ID3_FILE_FLAG_ID3V1) { - long length; - - if (vfs_fseek(file->iofile, 0, SEEK_END) == -1) - return -1; - - length = vfs_ftell(file->iofile); - if (length == -1 || - (length >= 0 && length < 128)) - return -1; - - if (vfs_truncate(file->iofile, length - 128) == -1) - return -1; - - /* delete file tag reference */ - - del_filetag(file, file->ntags - 1); - - file->flags &= ~ID3_FILE_FLAG_ID3V1; - } -# endif - - return 0; -} - -/* - * NAME: v2_write() - * DESCRIPTION: write ID3v2 tag modifications to a file - */ -static -int v2_write(struct id3_file *file, - id3_byte_t const *data, id3_length_t length) -{ -// assert(!data || length > 0); - - // delete tag request - if(!data && length == 0){ - int file_size; - int remainder_size; - char *remainder; - - /* read in the remainder of the file */ - vfs_fseek(file->iofile, 0, SEEK_END); - file_size = vfs_ftell(file->iofile); - remainder_size = file_size - file->tags[0].location - file->tags[0].length; - remainder = (char*)malloc(remainder_size); - - if (vfs_fseek(file->iofile, file->tags[0].location + file->tags[0].length, SEEK_SET) == -1 || - vfs_fread(remainder, remainder_size, 1, file->iofile) != 1) { - free(remainder); - return -1; - } - - /* write the remainder where the old tag was */ - if (vfs_fseek(file->iofile, file->tags[0].location, SEEK_SET) == -1 || - vfs_fwrite(remainder, remainder_size, 1, file->iofile) != 1) { - free(remainder); - return -1; - } - - free(remainder); - - /* flush the FILE */ -#ifndef AUDACIOUS - if (fflush(file->iofile) == EOF) - return -1; -#endif - /* truncate if required */ - if (vfs_ftell(file->iofile) < file_size) - vfs_truncate(file->iofile, vfs_ftell(file->iofile)); - - } - - // append a new id3v2 tag to the file which doesn't have any tag or only have v1tag. - if(data && - ((file->ntags == 0) || // no tag - (file->ntags == 1 && (file->flags & ID3_FILE_FLAG_ID3V1))) ) { // only v1 tag exists - - struct filetag filetag; - - printf("append v2tag\n"); - - filetag.tag = 0; - filetag.location = 0; // begining of the file. - filetag.length = 0; - - if(add_filetag(file, &filetag) == -1) - return -1; - - if(file->ntags == 1) - file->flags = 0; - if(file->ntags == 2) - file->flags |= ID3_FILE_FLAG_ID3V1; - } - - if (!data - || (!(file->ntags == 1 && !(file->flags & ID3_FILE_FLAG_ID3V1)) && - !(file->ntags == 2 && (file->flags & ID3_FILE_FLAG_ID3V1)))) { - /* no v2 tag. nothing to do */ - goto done; - } - - if (file->tags[0].length == length) { - /* easy special case: rewrite existing tag in-place */ - - if (vfs_fseek(file->iofile, file->tags[0].location, SEEK_SET) == -1 || -#ifdef AUDACIOUS - vfs_fwrite(data, length, 1, file->iofile) != 1) -#else - vfs_fwrite(data, length, 1, file->iofile) != 1 || - fflush(file->iofile) == EOF) -#endif - return -1; - - goto done; - } else { - /* the new tag has a different size */ - int file_size; - int remainder_size; - char *remainder; - - /* read in the remainder of the file */ - vfs_fseek(file->iofile, 0, SEEK_END); - file_size = vfs_ftell(file->iofile); - remainder_size = file_size - file->tags[0].location - file->tags[0].length; - remainder = (char*)malloc(remainder_size); - if (vfs_fseek(file->iofile, file->tags[0].location + file->tags[0].length, SEEK_SET) == -1 || - vfs_fread(remainder, remainder_size, 1, file->iofile) != 1) { - free(remainder); - return -1; - } - - /* write the tag where the old one was */ - if (vfs_fseek(file->iofile, file->tags[0].location, SEEK_SET) == -1 || - vfs_fwrite(data, length, 1, file->iofile) != 1) { - free(remainder); - return -1; - } - - /* write the reaminder */ - if (vfs_fwrite(remainder, remainder_size, 1, file->iofile) != 1) { - free(remainder); - return -1; - } - - free(remainder); - - /* flush the FILE */ -#ifndef AUDACIOUS - if (fflush(file->iofile) == EOF) - return -1; -#endif - /* truncate if required */ - if (vfs_ftell(file->iofile) < file_size) - vfs_truncate(file->iofile, vfs_ftell(file->iofile)); - } - - done: - return 0; -} - -/* - * NAME: file->update() - * DESCRIPTION: rewrite tag(s) to a file - */ -int id3_file_update(struct id3_file *file) -{ - int options, result = 0; - id3_length_t v1size = 0, v2size = 0; - id3_byte_t id3v1_data[128], *id3v1 = 0, *id3v2 = 0; - - assert(file); - - if (file->mode != ID3_FILE_MODE_READWRITE) - return -1; - - options = id3_tag_options(file->primary, 0, 0); - - /* render ID3v1 */ - - if (options & ID3_TAG_OPTION_ID3V1) { - v1size = id3_tag_render(file->primary, 0); - if (v1size) { - assert(v1size == sizeof(id3v1_data)); - - v1size = id3_tag_render(file->primary, id3v1_data); - if (v1size) { - assert(v1size == sizeof(id3v1_data)); - id3v1 = id3v1_data; - } - } - } - - /* render ID3v2 */ - - id3_tag_options(file->primary, ID3_TAG_OPTION_ID3V1, 0); - - v2size = id3_tag_render(file->primary, 0); - if (v2size) { - id3v2 = malloc(v2size); - if (id3v2 == 0) - goto fail; - - v2size = id3_tag_render(file->primary, id3v2); - if (v2size == 0) { - free(id3v2); - id3v2 = 0; - } - } - - /* write tags */ - - if (v2_write(file, id3v2, v2size) == -1 && - v1_write(file, id3v1, v1size) == -1) - goto fail; - - vfs_rewind(file->iofile); - - /* update file tags array? ... */ - - if (0) { - fail: - result = -1; - } - - /* clean up; restore tag options */ - - if (id3v2) - free(id3v2); - - id3_tag_options(file->primary, ~0, options); - - return result; -} diff --git a/src/libid3tag/file.h b/src/libid3tag/file.h deleted file mode 100644 index 032b189..0000000 --- a/src/libid3tag/file.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: file.h,v 1.8 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_FILE_H -# define LIBID3TAG_FILE_H - -# endif diff --git a/src/libid3tag/frame.c b/src/libid3tag/frame.c deleted file mode 100644 index 08710ff..0000000 --- a/src/libid3tag/frame.c +++ /dev/null @@ -1,627 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: frame.c,v 1.15 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <stdlib.h> -# include <stdio.h> -# include <string.h> - -# ifdef HAVE_ASSERT_H -# include <assert.h> -# endif - -# include "id3tag.h" -# include "frame.h" -# include "frametype.h" -# include "compat.h" -# include "field.h" -# include "render.h" -# include "parse.h" -# include "util.h" - -static -int valid_idchar(char c) -{ - return (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); -} - -/* - * NAME: frame->validid() - * DESCRIPTION: return true if the parameter string is a legal frame ID - */ -int id3_frame_validid(char const *id) -{ - return id && - valid_idchar(id[0]) && - valid_idchar(id[1]) && - valid_idchar(id[2]) && - valid_idchar(id[3]); -} - -/* - * NAME: frame->new() - * DESCRIPTION: allocate and return a new frame - */ -struct id3_frame *id3_frame_new(char const *id) -{ - struct id3_frametype const *frametype; - struct id3_frame *frame; - unsigned int i; - - if (!id3_frame_validid(id)) - return 0; - - frametype = id3_frametype_lookup(id, 4); - if (frametype == 0) { - switch (id[0]) { - case 'T': - frametype = &id3_frametype_text; - break; - - case 'W': - frametype = &id3_frametype_url; - break; - - case 'X': - case 'Y': - case 'Z': - frametype = &id3_frametype_experimental; - break; - - default: - frametype = &id3_frametype_unknown; - if (id3_compat_lookup(id, 4)) - frametype = &id3_frametype_obsolete; - break; - } - } - - frame = malloc(sizeof(*frame) + frametype->nfields * sizeof(*frame->fields)); - if (frame) { - frame->id[0] = id[0]; - frame->id[1] = id[1]; - frame->id[2] = id[2]; - frame->id[3] = id[3]; - frame->id[4] = 0; - - frame->description = frametype->description; - frame->refcount = 0; - frame->flags = frametype->defaultflags; - frame->group_id = 0; - frame->encryption_method = 0; - frame->encoded = 0; - frame->encoded_length = 0; - frame->decoded_length = 0; - frame->nfields = frametype->nfields; - frame->fields = (union id3_field *) &frame[1]; - - for (i = 0; i < frame->nfields; ++i) - id3_field_init(&frame->fields[i], frametype->fields[i]); - } - - return frame; -} - -void id3_frame_delete(struct id3_frame *frame) -{ - assert(frame); - - if (frame->refcount == 0) { - unsigned int i; - - for (i = 0; i < frame->nfields; ++i) - id3_field_finish(&frame->fields[i]); - - if (frame->encoded) - free(frame->encoded); - - free(frame); - } -} - -/* - * NAME: frame->addref() - * DESCRIPTION: add an external reference to a frame - */ -void id3_frame_addref(struct id3_frame *frame) -{ - assert(frame); - - ++frame->refcount; -} - -/* - * NAME: frame->delref() - * DESCRIPTION: remove an external reference to a frame - */ -void id3_frame_delref(struct id3_frame *frame) -{ - assert(frame && frame->refcount > 0); - - --frame->refcount; -} - -/* - * NAME: frame->field() - * DESCRIPTION: return a pointer to a field in a frame - */ -union id3_field *id3_frame_field(struct id3_frame const *frame, - unsigned int index) -{ - assert(frame); - - return (index < frame->nfields) ? &frame->fields[index] : 0; -} - -static -struct id3_frame *obsolete(char const *id, id3_byte_t const *data, - id3_length_t length) -{ - struct id3_frame *frame; - - frame = id3_frame_new(ID3_FRAME_OBSOLETE); - if (frame) { - if (id3_field_setframeid(&frame->fields[0], id) == -1 || - id3_field_setbinarydata(&frame->fields[1], data, length) == -1) - goto fail; - } - - if (0) { - fail: - if (frame) { - id3_frame_delete(frame); - frame = 0; - } - } - - return frame; -} - -static -struct id3_frame *unparseable(char const *id, id3_byte_t const **ptr, - id3_length_t length, int flags, - int group_id, int encryption_method, - id3_length_t decoded_length) -{ - struct id3_frame *frame = 0; - id3_byte_t *mem; - - mem = malloc(length ? length : 1); - if (mem == 0) - goto fail; - - frame = id3_frame_new(id); - if (frame == 0) - free(mem); - else { - memcpy(mem, *ptr, length); - - frame->flags = flags; - frame->group_id = group_id; - frame->encryption_method = encryption_method; - frame->encoded = mem; - frame->encoded_length = length; - frame->decoded_length = decoded_length; - } - - if (0) { - fail: - ; - } - - *ptr += length; - - return frame; -} - -static -int parse_data(struct id3_frame *frame, - id3_byte_t const *data, id3_length_t length) -{ - enum id3_field_textencoding encoding; - id3_byte_t const *end; - unsigned int i; - - encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1; - - end = data + length; - - for (i = 0; i < frame->nfields; ++i) { - if (id3_field_parse(&frame->fields[i], &data, end - data, &encoding) == -1) - return -1; - } - - return 0; -} - -/* - * NAME: frame->parse() - * DESCRIPTION: parse raw frame data according to the specified ID3 tag version - */ -struct id3_frame *id3_frame_parse(id3_byte_t const **ptr, id3_length_t length, - unsigned int version) -{ - struct id3_frame *frame = 0; - id3_byte_t const *id, *end, *data; - id3_length_t size, decoded_length = 0; - int flags = 0, group_id = 0, encryption_method = 0; - struct id3_compat const *compat = 0; - id3_byte_t *mem = 0; - char xid[4]; - - id = *ptr; - end = *ptr + length; - - if (ID3_TAG_VERSION_MAJOR(version) < 4) { - switch (ID3_TAG_VERSION_MAJOR(version)) { - case 2: - if (length < 6) - goto fail; - - compat = id3_compat_lookup((char *)id, 3); - - *ptr += 3; - size = id3_parse_uint(ptr, 3); - - if (size > end - *ptr) - goto fail; - - end = *ptr + size; - - break; - - case 3: - if (length < 10) - goto fail; - - compat = id3_compat_lookup((char *)id, 4); - - *ptr += 4; - size = id3_parse_uint(ptr, 4); - flags = id3_parse_uint(ptr, 2); - - if (size > end - *ptr) - goto fail; - - end = *ptr + size; - - if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~0x00e0)) { - frame = unparseable((char *)id, ptr, end - *ptr, 0, 0, 0, 0); - goto done; - } - - flags = - ((flags >> 1) & ID3_FRAME_FLAG_STATUSFLAGS) | - ((flags >> 4) & (ID3_FRAME_FLAG_COMPRESSION | - ID3_FRAME_FLAG_ENCRYPTION)) | - ((flags << 1) & ID3_FRAME_FLAG_GROUPINGIDENTITY); - - if (flags & ID3_FRAME_FLAG_COMPRESSION) { - if (end - *ptr < 4) - goto fail; - - decoded_length = id3_parse_uint(ptr, 4); - } - - if (flags & ID3_FRAME_FLAG_ENCRYPTION) { - if (end - *ptr < 1) - goto fail; - - encryption_method = id3_parse_uint(ptr, 1); - } - - if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) { - if (end - *ptr < 1) - goto fail; - - group_id = id3_parse_uint(ptr, 1); - } - - break; - - default: - goto fail; - } - - /* canonicalize frame ID for ID3v2.4 */ - - if (compat && compat->equiv) - id = (id3_byte_t *)compat->equiv; - else if (ID3_TAG_VERSION_MAJOR(version) == 2) { - xid[0] = 'Y'; - xid[1] = id[0]; - xid[2] = id[1]; - xid[3] = id[2]; - - id = (id3_byte_t *)xid; - - flags |= - ID3_FRAME_FLAG_TAGALTERPRESERVATION | - ID3_FRAME_FLAG_FILEALTERPRESERVATION; - } - } - else { /* ID3v2.4 */ - if (length < 10) - goto fail; - - *ptr += 4; - size = id3_parse_syncsafe(ptr, 4); - flags = id3_parse_uint(ptr, 2); - - if (size > end - *ptr) - goto fail; - - end = *ptr + size; - - if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) { - frame = unparseable((char *)id, ptr, end - *ptr, flags, 0, 0, 0); - goto done; - } - - if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) { - if (end - *ptr < 1) - goto fail; - - group_id = id3_parse_uint(ptr, 1); - } - - if ((flags & ID3_FRAME_FLAG_COMPRESSION) && - !(flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR)) - goto fail; - - if (flags & ID3_FRAME_FLAG_ENCRYPTION) { - if (end - *ptr < 1) - goto fail; - - encryption_method = id3_parse_uint(ptr, 1); - } - - if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) { - if (end - *ptr < 4) - goto fail; - - decoded_length = id3_parse_syncsafe(ptr, 4); - } - } - - data = *ptr; - *ptr = end; - - /* undo frame encodings */ - - if ((flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) && end - data > 0) { - mem = malloc(end - data); - if (mem == 0) - goto fail; - - memcpy(mem, data, end - data); - - end = mem + id3_util_deunsynchronise(mem, end - data); - data = mem; - } - - if (flags & ID3_FRAME_FLAG_ENCRYPTION) { - frame = unparseable((char *)id, &data, end - data, flags, - group_id, encryption_method, decoded_length); - goto done; - } - - if (flags & ID3_FRAME_FLAG_COMPRESSION) { - id3_byte_t *decomp; - - decomp = id3_util_decompress(data, end - data, decoded_length); - if (decomp == 0) - goto fail; - - if (mem) - free(mem); - - data = mem = decomp; - end = data + decoded_length; - } - - /* check for obsolescence */ - - if (compat && !compat->equiv) { - frame = obsolete((char *)id, data, end - data); - goto done; - } - - /* generate the internal frame structure */ - - frame = id3_frame_new((char *)id); - if (frame) { - frame->flags = flags; - frame->group_id = group_id; - - if (compat && compat->translate) { - if (compat->translate(frame, compat->id, data, end - data) == -1) - goto fail; - } - else { - if (parse_data(frame, data, end - data) == -1) - goto fail; - } - } - - if (0) { - fail: - if (frame) { - id3_frame_delete(frame); - frame = 0; - } - } - - done: - if (mem) - free(mem); - - return frame; -} - -static -id3_length_t render_data(id3_byte_t **ptr, - union id3_field *fields, unsigned int length) -{ - id3_length_t size = 0; - enum id3_field_textencoding encoding; - unsigned int i; - - encoding = ID3_FIELD_TEXTENCODING_ISO_8859_1; //here!! --yaz - fflush(NULL); - for (i = 0; i < length; ++i) - size += id3_field_render(&fields[i], ptr, &encoding, i < length - 1); - - return size; -} - -/* - * NAME: frame->render() - * DESCRIPTION: render a single, complete frame - */ -id3_length_t id3_frame_render(struct id3_frame const *frame, - id3_byte_t **ptr, int options) -{ - id3_length_t size = 0, decoded_length, datalen; - id3_byte_t *size_ptr = 0, *flags_ptr = 0, *data = 0; - int flags; - - assert(frame); - - if ((frame->flags & ID3_FRAME_FLAG_TAGALTERPRESERVATION) || - ((options & ID3_TAG_OPTION_FILEALTERED) && - (frame->flags & ID3_FRAME_FLAG_FILEALTERPRESERVATION))) - return 0; - - /* a frame must be at least 1 byte big, excluding the header */ - - decoded_length = render_data(0, frame->fields, frame->nfields); - if (decoded_length == 0 && frame->encoded == 0) - return 0; - - /* header */ - - size += id3_render_immediate(ptr, frame->id, 4); - - if (ptr) - size_ptr = *ptr; - - size += id3_render_syncsafe(ptr, 0, 4); - - if (ptr) - flags_ptr = *ptr; - - flags = frame->flags; - - size += id3_render_int(ptr, flags, 2); - - if (flags & (ID3_FRAME_FLAG_FORMATFLAGS & ~ID3_FRAME_FLAG_KNOWNFLAGS)) { - size += id3_render_binary(ptr, frame->encoded, frame->encoded_length); - if (size_ptr) - id3_render_syncsafe(&size_ptr, size - 10, 4); - - return size; - } - - flags &= ID3_FRAME_FLAG_KNOWNFLAGS; - - flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION; - if (options & ID3_TAG_OPTION_UNSYNCHRONISATION) - flags |= ID3_FRAME_FLAG_UNSYNCHRONISATION; - - if (!(flags & ID3_FRAME_FLAG_ENCRYPTION)) { - flags &= ~ID3_FRAME_FLAG_COMPRESSION; - if (options & ID3_TAG_OPTION_COMPRESSION) - flags |= ID3_FRAME_FLAG_COMPRESSION | ID3_FRAME_FLAG_DATALENGTHINDICATOR; - } - - if (flags & ID3_FRAME_FLAG_GROUPINGIDENTITY) - size += id3_render_int(ptr, frame->group_id, 1); - if (flags & ID3_FRAME_FLAG_ENCRYPTION) - size += id3_render_int(ptr, frame->encryption_method, 1); - if (flags & ID3_FRAME_FLAG_DATALENGTHINDICATOR) { - if (flags & ID3_FRAME_FLAG_ENCRYPTION) - decoded_length = frame->decoded_length; - size += id3_render_syncsafe(ptr, decoded_length, 4); - } - - if (ptr) - data = *ptr; - - if (flags & ID3_FRAME_FLAG_ENCRYPTION) - datalen = id3_render_binary(ptr, frame->encoded, frame->encoded_length); - else { - if (ptr == 0) - datalen = decoded_length; - else { - datalen = render_data(ptr, frame->fields, frame->nfields); - - if (flags & ID3_FRAME_FLAG_COMPRESSION) { - id3_byte_t *comp; - id3_length_t complen; - - comp = id3_util_compress(data, datalen, &complen); - if (comp == 0) - flags &= ~ID3_FRAME_FLAG_COMPRESSION; - else { - *ptr = data; - datalen = id3_render_binary(ptr, comp, complen); - - free(comp); - } - } - } - } - - /* unsynchronisation */ - - if (flags & ID3_FRAME_FLAG_UNSYNCHRONISATION) { - if (data == 0) - datalen *= 2; - else { - id3_length_t newlen; - - newlen = id3_util_unsynchronise(data, datalen); - if (newlen == datalen) - flags &= ~ID3_FRAME_FLAG_UNSYNCHRONISATION; - else { - *ptr += newlen - datalen; - datalen = newlen; - } - } - } - - size += datalen; - - /* patch size and flags */ - - if (size_ptr) - id3_render_syncsafe(&size_ptr, size - 10, 4); - if (flags_ptr) - id3_render_int(&flags_ptr, flags, 2); - - return size; -} diff --git a/src/libid3tag/frame.h b/src/libid3tag/frame.h deleted file mode 100644 index 05c6b04..0000000 --- a/src/libid3tag/frame.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: frame.h,v 1.8 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_FRAME_H -# define LIBID3TAG_FRAME_H - -# include "id3tag.h" - -int id3_frame_validid(char const *); - -void id3_frame_addref(struct id3_frame *); -void id3_frame_delref(struct id3_frame *); - -struct id3_frame *id3_frame_parse(id3_byte_t const **, id3_length_t, - unsigned int); -id3_length_t id3_frame_render(struct id3_frame const *, id3_byte_t **, int); - -# endif diff --git a/src/libid3tag/frametype.c b/src/libid3tag/frametype.c deleted file mode 100644 index 13c5001..0000000 --- a/src/libid3tag/frametype.c +++ /dev/null @@ -1,568 +0,0 @@ -/* C code produced by gperf version 3.0.1 */ -/* Command-line: gperf -tCcTonD -K id -N id3_frametype_lookup -s -3 -k '*' frametype.gperf */ - -#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ - && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ - && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ - && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ - && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ - && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ - && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ - && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ - && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ - && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ - && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ - && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ - && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ - && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ - && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ - && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ - && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ - && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ - && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ - && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ - && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ - && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ - && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) -/* The character set is not based on ISO-646. */ -error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>." -#endif - -#line 1 "frametype.gperf" - -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Id: frametype.gperf,v 1.7 2004/01/23 09:41:32 rob Exp - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <string.h> - -# include "id3tag.h" -# include "frametype.h" - -# define FIELDS(id) static enum id3_field_type const fields_##id[] - -/* frame field descriptions */ - -FIELDS(UFID) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(TXXX) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_STRING -}; - -FIELDS(WXXX) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_LATIN1 -}; - -FIELDS(MCDI) = { - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(ETCO) = { - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(MLLT) = { - ID3_FIELD_TYPE_INT16, - ID3_FIELD_TYPE_INT24, - ID3_FIELD_TYPE_INT24, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(SYTC) = { - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(USLT) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LANGUAGE, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_STRINGFULL -}; - -FIELDS(SYLT) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LANGUAGE, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(COMM) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LANGUAGE, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_STRINGFULL -}; - -FIELDS(RVA2) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(EQU2) = { - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(RVRB) = { - ID3_FIELD_TYPE_INT16, - ID3_FIELD_TYPE_INT16, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8 -}; - -FIELDS(APIC) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(GEOB) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(PCNT) = { - ID3_FIELD_TYPE_INT32PLUS -}; - -FIELDS(POPM) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT32PLUS -}; - -FIELDS(RBUF) = { - ID3_FIELD_TYPE_INT24, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT32 -}; - -FIELDS(AENC) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_INT16, - ID3_FIELD_TYPE_INT16, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(LINK) = { - ID3_FIELD_TYPE_FRAMEID, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_LATIN1LIST -}; - -FIELDS(POSS) = { - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(USER) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LANGUAGE, - ID3_FIELD_TYPE_STRING -}; - -FIELDS(OWNE) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_DATE, - ID3_FIELD_TYPE_STRING -}; - -FIELDS(COMR) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_DATE, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(ENCR) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(GRID) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(PRIV) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(SIGN) = { - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(SEEK) = { - ID3_FIELD_TYPE_INT32 -}; - -FIELDS(ASPI) = { - ID3_FIELD_TYPE_INT32, - ID3_FIELD_TYPE_INT32, - ID3_FIELD_TYPE_INT16, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(text) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_STRINGLIST -}; - -FIELDS(url) = { - ID3_FIELD_TYPE_LATIN1 -}; - -FIELDS(unknown) = { - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(ZOBS) = { - ID3_FIELD_TYPE_FRAMEID, - ID3_FIELD_TYPE_BINARYDATA -}; - -# define FRAME(id) \ - sizeof(fields_##id) / sizeof(fields_##id[0]), fields_##id - -# define PRESERVE 0 -# define DISCARD ID3_FRAME_FLAG_FILEALTERPRESERVATION -# define OBSOLETE (DISCARD | ID3_FRAME_FLAG_TAGALTERPRESERVATION) - -# define FRAMETYPE(type, id, flags, desc) \ - struct id3_frametype const id3_frametype_##type = { \ - 0, FRAME(id), flags, desc \ - } - -/* static frame types */ - -FRAMETYPE(text, text, PRESERVE, "Unknown text information frame"); -FRAMETYPE(url, url, PRESERVE, "Unknown URL link frame"); -FRAMETYPE(experimental, unknown, PRESERVE, "Experimental frame"); -FRAMETYPE(unknown, unknown, PRESERVE, "Unknown frame"); -FRAMETYPE(obsolete, unknown, OBSOLETE, "Obsolete frame"); - -#define TOTAL_KEYWORDS 84 -#define MIN_WORD_LENGTH 4 -#define MAX_WORD_LENGTH 4 -#define MIN_HASH_VALUE 7 -#define MAX_HASH_VALUE 155 -/* maximum key range = 149, duplicates = 0 */ - -#ifdef __GNUC__ -__inline -#else -#ifdef __cplusplus -inline -#endif -#endif -static unsigned int -hash (str, len) - register const char *str; - register unsigned int len; -{ - static const unsigned char asso_values[] = - { - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 43, 4, 47, 49, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 31, 53, 3, 15, 3, - 24, 25, 10, 52, 69, 34, 23, 30, 1, 5, - 10, 62, 20, 0, 28, 28, 22, 19, 47, 3, - 10, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, - 156, 156, 156, 156, 156, 156, 156 - }; - return asso_values[(unsigned char)str[3]+1] + asso_values[(unsigned char)str[2]] + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]]; -} - -#ifdef __GNUC__ -__inline -#endif -const struct id3_frametype * -id3_frametype_lookup (str, len) - register const char *str; - register unsigned int len; -{ - static const struct id3_frametype wordlist[] = - { -#line 282 "frametype.gperf" - {"ENCR", FRAME(ENCR), PRESERVE, "Encryption method registration"}, -#line 292 "frametype.gperf" - {"POPM", FRAME(POPM), PRESERVE, "Popularimeter"}, -#line 351 "frametype.gperf" - {"WCOM", FRAME(url), PRESERVE, "Commercial information"}, -#line 298 "frametype.gperf" - {"SEEK", FRAME(SEEK), DISCARD, "Seek frame"}, -#line 349 "frametype.gperf" - {"USER", FRAME(USER), PRESERVE, "Terms of use"}, -#line 285 "frametype.gperf" - {"GEOB", FRAME(GEOB), PRESERVE, "General encapsulated object"}, -#line 304 "frametype.gperf" - {"TCOM", FRAME(text), PRESERVE, "Composer"}, -#line 281 "frametype.gperf" - {"COMR", FRAME(COMR), PRESERVE, "Commercial frame"}, -#line 280 "frametype.gperf" - {"COMM", FRAME(COMM), PRESERVE, "Comments"}, -#line 305 "frametype.gperf" - {"TCON", FRAME(text), PRESERVE, "Content type"}, -#line 291 "frametype.gperf" - {"PCNT", FRAME(PCNT), PRESERVE, "Play counter"}, -#line 293 "frametype.gperf" - {"POSS", FRAME(POSS), DISCARD, "Position synchronisation frame"}, -#line 284 "frametype.gperf" - {"ETCO", FRAME(ETCO), DISCARD, "Event timing codes"}, -#line 332 "frametype.gperf" - {"TPE2", FRAME(text), PRESERVE, "Band/orchestra/accompaniment"}, -#line 301 "frametype.gperf" - {"SYTC", FRAME(SYTC), DISCARD, "Synchronised tempo codes"}, -#line 313 "frametype.gperf" - {"TENC", FRAME(text), DISCARD, "Encoded by"}, -#line 309 "frametype.gperf" - {"TDOR", FRAME(text), PRESERVE, "Original release time"}, -#line 290 "frametype.gperf" - {"OWNE", FRAME(OWNE), PRESERVE, "Ownership frame"}, -#line 277 "frametype.gperf" - {"AENC", FRAME(AENC), DISCARD, "Audio encryption"}, -#line 307 "frametype.gperf" - {"TDEN", FRAME(text), PRESERVE, "Encoding time"}, -#line 345 "frametype.gperf" - {"TSSE", FRAME(text), PRESERVE, "Software/hardware and settings used for encoding"}, -#line 339 "frametype.gperf" - {"TRSN", FRAME(text), PRESERVE, "Internet radio station name"}, -#line 300 "frametype.gperf" - {"SYLT", FRAME(SYLT), DISCARD, "Synchronised lyric/text"}, -#line 354 "frametype.gperf" - {"WOAR", FRAME(url), PRESERVE, "Official artist/performer webpage"}, -#line 346 "frametype.gperf" - {"TSST", FRAME(text), PRESERVE, "Set subtitle"}, -#line 330 "frametype.gperf" - {"TOWN", FRAME(text), PRESERVE, "File owner/licensee"}, -#line 340 "frametype.gperf" - {"TRSO", FRAME(text), PRESERVE, "Internet radio station owner"}, -#line 322 "frametype.gperf" - {"TLEN", FRAME(text), DISCARD, "Length"}, -#line 358 "frametype.gperf" - {"WPUB", FRAME(url), PRESERVE, "Publishers official webpage"}, -#line 343 "frametype.gperf" - {"TSOT", FRAME(text), PRESERVE, "Title sort order"}, -#line 327 "frametype.gperf" - {"TOFN", FRAME(text), PRESERVE, "Original filename"}, -#line 344 "frametype.gperf" - {"TSRC", FRAME(text), PRESERVE, "ISRC (international standard recording code)"}, -#line 324 "frametype.gperf" - {"TMED", FRAME(text), PRESERVE, "Media type"}, -#line 297 "frametype.gperf" - {"RVRB", FRAME(RVRB), PRESERVE, "Reverb"}, -#line 328 "frametype.gperf" - {"TOLY", FRAME(text), PRESERVE, "Original lyricist(s)/text writer(s)"}, -#line 329 "frametype.gperf" - {"TOPE", FRAME(text), PRESERVE, "Original artist(s)/performer(s)"}, -#line 336 "frametype.gperf" - {"TPRO", FRAME(text), PRESERVE, "Produced notice"}, -#line 337 "frametype.gperf" - {"TPUB", FRAME(text), PRESERVE, "Publisher"}, -#line 357 "frametype.gperf" - {"WPAY", FRAME(url), PRESERVE, "Payment"}, -#line 335 "frametype.gperf" - {"TPOS", FRAME(text), PRESERVE, "Part of a set"}, -#line 356 "frametype.gperf" - {"WORS", FRAME(url), PRESERVE, "Official Internet radio station homepage"}, -#line 325 "frametype.gperf" - {"TMOO", FRAME(text), PRESERVE, "Mood"}, -#line 338 "frametype.gperf" - {"TRCK", FRAME(text), PRESERVE, "Track number/position in set"}, -#line 320 "frametype.gperf" - {"TKEY", FRAME(text), PRESERVE, "Initial key"}, -#line 308 "frametype.gperf" - {"TDLY", FRAME(text), PRESERVE, "Playlist delay"}, -#line 296 "frametype.gperf" - {"RVA2", FRAME(RVA2), DISCARD, "Relative volume adjustment (2)"}, -#line 310 "frametype.gperf" - {"TDRC", FRAME(text), PRESERVE, "Recording time"}, -#line 350 "frametype.gperf" - {"USLT", FRAME(USLT), PRESERVE, "Unsynchronised lyric/text transcription"}, -#line 353 "frametype.gperf" - {"WOAF", FRAME(url), PRESERVE, "Official audio file webpage"}, -#line 312 "frametype.gperf" - {"TDTG", FRAME(text), PRESERVE, "Tagging time"}, -#line 299 "frametype.gperf" - {"SIGN", FRAME(SIGN), PRESERVE, "Signature frame"}, -#line 355 "frametype.gperf" - {"WOAS", FRAME(url), PRESERVE, "Official audio source webpage"}, -#line 331 "frametype.gperf" - {"TPE1", FRAME(text), PRESERVE, "Lead performer(s)/soloist(s)"}, -#line 302 "frametype.gperf" - {"TALB", FRAME(text), PRESERVE, "Album/movie/show title"}, -#line 341 "frametype.gperf" - {"TSOA", FRAME(text), PRESERVE, "Album sort order"}, -#line 321 "frametype.gperf" - {"TLAN", FRAME(text), PRESERVE, "Language(s)"}, -#line 333 "frametype.gperf" - {"TPE3", FRAME(text), PRESERVE, "Conductor/performer refinement"}, -#line 352 "frametype.gperf" - {"WCOP", FRAME(url), PRESERVE, "Copyright/legal information"}, -#line 334 "frametype.gperf" - {"TPE4", FRAME(text), PRESERVE, "Interpreted, remixed, or otherwise modified by"}, -#line 323 "frametype.gperf" - {"TMCL", FRAME(text), PRESERVE, "Musician credits list"}, -#line 303 "frametype.gperf" - {"TBPM", FRAME(text), PRESERVE, "BPM (beats per minute)"}, -#line 311 "frametype.gperf" - {"TDRL", FRAME(text), PRESERVE, "Release time"}, -#line 326 "frametype.gperf" - {"TOAL", FRAME(text), PRESERVE, "Original album/movie/show title"}, -#line 342 "frametype.gperf" - {"TSOP", FRAME(text), PRESERVE, "Performer sort order"}, -#line 363 "frametype.gperf" - {"ZOBS", FRAME(ZOBS), OBSOLETE, "Obsolete frame"}, -#line 283 "frametype.gperf" - {"EQU2", FRAME(EQU2), DISCARD, "Equalisation (2)"}, -#line 306 "frametype.gperf" - {"TCOP", FRAME(text), PRESERVE, "Copyright message"}, -#line 287 "frametype.gperf" - {"LINK", FRAME(LINK), PRESERVE, "Linked information"}, -#line 286 "frametype.gperf" - {"GRID", FRAME(GRID), PRESERVE, "Group identification registration"}, -#line 294 "frametype.gperf" - {"PRIV", FRAME(PRIV), PRESERVE, "Private frame"}, -#line 315 "frametype.gperf" - {"TFLT", FRAME(text), PRESERVE, "File type"}, -#line 289 "frametype.gperf" - {"MLLT", FRAME(MLLT), DISCARD, "MPEG location lookup table"}, -#line 314 "frametype.gperf" - {"TEXT", FRAME(text), PRESERVE, "Lyricist/text writer"}, -#line 348 "frametype.gperf" - {"UFID", FRAME(UFID), PRESERVE, "Unique file identifier"}, -#line 278 "frametype.gperf" - {"APIC", FRAME(APIC), PRESERVE, "Attached picture"}, -#line 279 "frametype.gperf" - {"ASPI", FRAME(ASPI), DISCARD, "Audio seek point index"}, -#line 318 "frametype.gperf" - {"TIT2", FRAME(text), PRESERVE, "Title/songname/content description"}, -#line 359 "frametype.gperf" - {"WXXX", FRAME(WXXX), PRESERVE, "User defined URL link frame"}, -#line 288 "frametype.gperf" - {"MCDI", FRAME(MCDI), PRESERVE, "Music CD identifier"}, -#line 316 "frametype.gperf" - {"TIPL", FRAME(text), PRESERVE, "Involved people list"}, -#line 347 "frametype.gperf" - {"TXXX", FRAME(TXXX), PRESERVE, "User defined text information frame"}, -#line 295 "frametype.gperf" - {"RBUF", FRAME(RBUF), PRESERVE, "Recommended buffer size"}, -#line 317 "frametype.gperf" - {"TIT1", FRAME(text), PRESERVE, "Content group description"}, -#line 319 "frametype.gperf" - {"TIT3", FRAME(text), PRESERVE, "Subtitle/description refinement"} - }; - - static const short lookup[] = - { - -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, - 2, 3, -1, 4, -1, -1, -1, -1, 5, 6, 7, 8, -1, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, -1, 70, 71, -1, 72, 73, 74, -1, 75, -1, - 76, -1, -1, -1, 77, 78, -1, -1, 79, -1, -1, -1, -1, 80, - 81, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, -1, -1, - -1, 83 - }; - - if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) - { - register int key = hash (str, len); - - if (key <= MAX_HASH_VALUE && key >= 0) - { - register int index = lookup[key]; - - if (index >= 0) - { - register const char *s = wordlist[index].id; - - if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') - return &wordlist[index]; - } - } - } - return 0; -} diff --git a/src/libid3tag/frametype.gperf b/src/libid3tag/frametype.gperf deleted file mode 100644 index 1c8ff2e..0000000 --- a/src/libid3tag/frametype.gperf +++ /dev/null @@ -1,363 +0,0 @@ -%{ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: frametype.gperf,v 1.7 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <string.h> - -# include "id3tag.h" -# include "frametype.h" - -# define FIELDS(id) static enum id3_field_type const fields_##id[] - -/* frame field descriptions */ - -FIELDS(UFID) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(TXXX) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_STRING -}; - -FIELDS(WXXX) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_LATIN1 -}; - -FIELDS(MCDI) = { - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(ETCO) = { - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(MLLT) = { - ID3_FIELD_TYPE_INT16, - ID3_FIELD_TYPE_INT24, - ID3_FIELD_TYPE_INT24, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(SYTC) = { - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(USLT) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LANGUAGE, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_STRINGFULL -}; - -FIELDS(SYLT) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LANGUAGE, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(COMM) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LANGUAGE, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_STRINGFULL -}; - -FIELDS(RVA2) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(EQU2) = { - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(RVRB) = { - ID3_FIELD_TYPE_INT16, - ID3_FIELD_TYPE_INT16, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT8 -}; - -FIELDS(APIC) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(GEOB) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(PCNT) = { - ID3_FIELD_TYPE_INT32PLUS -}; - -FIELDS(POPM) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT32PLUS -}; - -FIELDS(RBUF) = { - ID3_FIELD_TYPE_INT24, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT32 -}; - -FIELDS(AENC) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_INT16, - ID3_FIELD_TYPE_INT16, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(LINK) = { - ID3_FIELD_TYPE_FRAMEID, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_LATIN1LIST -}; - -FIELDS(POSS) = { - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(USER) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LANGUAGE, - ID3_FIELD_TYPE_STRING -}; - -FIELDS(OWNE) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_DATE, - ID3_FIELD_TYPE_STRING -}; - -FIELDS(COMR) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_DATE, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(ENCR) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(GRID) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(PRIV) = { - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(SIGN) = { - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(SEEK) = { - ID3_FIELD_TYPE_INT32 -}; - -FIELDS(ASPI) = { - ID3_FIELD_TYPE_INT32, - ID3_FIELD_TYPE_INT32, - ID3_FIELD_TYPE_INT16, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(text) = { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_STRINGLIST -}; - -FIELDS(url) = { - ID3_FIELD_TYPE_LATIN1 -}; - -FIELDS(unknown) = { - ID3_FIELD_TYPE_BINARYDATA -}; - -FIELDS(ZOBS) = { - ID3_FIELD_TYPE_FRAMEID, - ID3_FIELD_TYPE_BINARYDATA -}; - -# define FRAME(id) \ - sizeof(fields_##id) / sizeof(fields_##id[0]), fields_##id - -# define PRESERVE 0 -# define DISCARD ID3_FRAME_FLAG_FILEALTERPRESERVATION -# define OBSOLETE (DISCARD | ID3_FRAME_FLAG_TAGALTERPRESERVATION) - -# define FRAMETYPE(type, id, flags, desc) \ - struct id3_frametype const id3_frametype_##type = { \ - 0, FRAME(id), flags, desc \ - } - -/* static frame types */ - -FRAMETYPE(text, text, PRESERVE, "Unknown text information frame"); -FRAMETYPE(url, url, PRESERVE, "Unknown URL link frame"); -FRAMETYPE(experimental, unknown, PRESERVE, "Experimental frame"); -FRAMETYPE(unknown, unknown, PRESERVE, "Unknown frame"); -FRAMETYPE(obsolete, unknown, OBSOLETE, "Obsolete frame"); -%} -struct id3_frametype; -%% -# -# ID3v2.4 frames -# -AENC, FRAME(AENC), DISCARD, "Audio encryption" -APIC, FRAME(APIC), PRESERVE, "Attached picture" -ASPI, FRAME(ASPI), DISCARD, "Audio seek point index" -COMM, FRAME(COMM), PRESERVE, "Comments" -COMR, FRAME(COMR), PRESERVE, "Commercial frame" -ENCR, FRAME(ENCR), PRESERVE, "Encryption method registration" -EQU2, FRAME(EQU2), DISCARD, "Equalisation (2)" -ETCO, FRAME(ETCO), DISCARD, "Event timing codes" -GEOB, FRAME(GEOB), PRESERVE, "General encapsulated object" -GRID, FRAME(GRID), PRESERVE, "Group identification registration" -LINK, FRAME(LINK), PRESERVE, "Linked information" -MCDI, FRAME(MCDI), PRESERVE, "Music CD identifier" -MLLT, FRAME(MLLT), DISCARD, "MPEG location lookup table" -OWNE, FRAME(OWNE), PRESERVE, "Ownership frame" -PCNT, FRAME(PCNT), PRESERVE, "Play counter" -POPM, FRAME(POPM), PRESERVE, "Popularimeter" -POSS, FRAME(POSS), DISCARD, "Position synchronisation frame" -PRIV, FRAME(PRIV), PRESERVE, "Private frame" -RBUF, FRAME(RBUF), PRESERVE, "Recommended buffer size" -RVA2, FRAME(RVA2), DISCARD, "Relative volume adjustment (2)" -RVRB, FRAME(RVRB), PRESERVE, "Reverb" -SEEK, FRAME(SEEK), DISCARD, "Seek frame" -SIGN, FRAME(SIGN), PRESERVE, "Signature frame" -SYLT, FRAME(SYLT), DISCARD, "Synchronised lyric/text" -SYTC, FRAME(SYTC), DISCARD, "Synchronised tempo codes" -TALB, FRAME(text), PRESERVE, "Album/movie/show title" -TBPM, FRAME(text), PRESERVE, "BPM (beats per minute)" -TCOM, FRAME(text), PRESERVE, "Composer" -TCON, FRAME(text), PRESERVE, "Content type" -TCOP, FRAME(text), PRESERVE, "Copyright message" -TDEN, FRAME(text), PRESERVE, "Encoding time" -TDLY, FRAME(text), PRESERVE, "Playlist delay" -TDOR, FRAME(text), PRESERVE, "Original release time" -TDRC, FRAME(text), PRESERVE, "Recording time" -TDRL, FRAME(text), PRESERVE, "Release time" -TDTG, FRAME(text), PRESERVE, "Tagging time" -TENC, FRAME(text), DISCARD, "Encoded by" -TEXT, FRAME(text), PRESERVE, "Lyricist/text writer" -TFLT, FRAME(text), PRESERVE, "File type" -TIPL, FRAME(text), PRESERVE, "Involved people list" -TIT1, FRAME(text), PRESERVE, "Content group description" -TIT2, FRAME(text), PRESERVE, "Title/songname/content description" -TIT3, FRAME(text), PRESERVE, "Subtitle/description refinement" -TKEY, FRAME(text), PRESERVE, "Initial key" -TLAN, FRAME(text), PRESERVE, "Language(s)" -TLEN, FRAME(text), DISCARD, "Length" -TMCL, FRAME(text), PRESERVE, "Musician credits list" -TMED, FRAME(text), PRESERVE, "Media type" -TMOO, FRAME(text), PRESERVE, "Mood" -TOAL, FRAME(text), PRESERVE, "Original album/movie/show title" -TOFN, FRAME(text), PRESERVE, "Original filename" -TOLY, FRAME(text), PRESERVE, "Original lyricist(s)/text writer(s)" -TOPE, FRAME(text), PRESERVE, "Original artist(s)/performer(s)" -TOWN, FRAME(text), PRESERVE, "File owner/licensee" -TPE1, FRAME(text), PRESERVE, "Lead performer(s)/soloist(s)" -TPE2, FRAME(text), PRESERVE, "Band/orchestra/accompaniment" -TPE3, FRAME(text), PRESERVE, "Conductor/performer refinement" -TPE4, FRAME(text), PRESERVE, "Interpreted, remixed, or otherwise modified by" -TPOS, FRAME(text), PRESERVE, "Part of a set" -TPRO, FRAME(text), PRESERVE, "Produced notice" -TPUB, FRAME(text), PRESERVE, "Publisher" -TRCK, FRAME(text), PRESERVE, "Track number/position in set" -TRSN, FRAME(text), PRESERVE, "Internet radio station name" -TRSO, FRAME(text), PRESERVE, "Internet radio station owner" -TSOA, FRAME(text), PRESERVE, "Album sort order" -TSOP, FRAME(text), PRESERVE, "Performer sort order" -TSOT, FRAME(text), PRESERVE, "Title sort order" -TSRC, FRAME(text), PRESERVE, "ISRC (international standard recording code)" -TSSE, FRAME(text), PRESERVE, "Software/hardware and settings used for encoding" -TSST, FRAME(text), PRESERVE, "Set subtitle" -TXXX, FRAME(TXXX), PRESERVE, "User defined text information frame" -UFID, FRAME(UFID), PRESERVE, "Unique file identifier" -USER, FRAME(USER), PRESERVE, "Terms of use" -USLT, FRAME(USLT), PRESERVE, "Unsynchronised lyric/text transcription" -WCOM, FRAME(url), PRESERVE, "Commercial information" -WCOP, FRAME(url), PRESERVE, "Copyright/legal information" -WOAF, FRAME(url), PRESERVE, "Official audio file webpage" -WOAR, FRAME(url), PRESERVE, "Official artist/performer webpage" -WOAS, FRAME(url), PRESERVE, "Official audio source webpage" -WORS, FRAME(url), PRESERVE, "Official Internet radio station homepage" -WPAY, FRAME(url), PRESERVE, "Payment" -WPUB, FRAME(url), PRESERVE, "Publishers official webpage" -WXXX, FRAME(WXXX), PRESERVE, "User defined URL link frame" -# -# Special frames -# -ZOBS, FRAME(ZOBS), OBSOLETE, "Obsolete frame" diff --git a/src/libid3tag/frametype.h b/src/libid3tag/frametype.h deleted file mode 100644 index dd064b2..0000000 --- a/src/libid3tag/frametype.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: frametype.h,v 1.7 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_FRAMETYPE_H -# define LIBID3TAG_FRAMETYPE_H - -struct id3_frametype { - char const *id; - unsigned int nfields; - enum id3_field_type const *fields; - int defaultflags; - char const *description; -}; - -extern struct id3_frametype const id3_frametype_text; -extern struct id3_frametype const id3_frametype_url; -extern struct id3_frametype const id3_frametype_experimental; -extern struct id3_frametype const id3_frametype_unknown; -extern struct id3_frametype const id3_frametype_obsolete; - -struct id3_frametype const *id3_frametype_lookup(register char const *, - register unsigned int); - -# endif diff --git a/src/libid3tag/genre.c b/src/libid3tag/genre.c deleted file mode 100644 index 9721101..0000000 --- a/src/libid3tag/genre.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: genre.c,v 1.8 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include "id3tag.h" -# include "ucs4.h" - -/* genres are stored in ucs4 format */ -# include "genre.dat" - -# define NGENRES (sizeof(genre_table) / sizeof(genre_table[0])) - -/* - * NAME: genre->index() - * DESCRIPTION: return an ID3v1 genre string indexed by number - */ -id3_ucs4_t const *id3_genre_index(unsigned int index) -{ - return (index < NGENRES) ? genre_table[index] : 0; -} - -/* - * NAME: genre->name() - * DESCRIPTION: translate an ID3v2 genre number/keyword to its full name - */ -id3_ucs4_t const *id3_genre_name(id3_ucs4_t const *string) -{ - id3_ucs4_t *ptr; - static id3_ucs4_t const genre_remix[] = { 'R', 'e', 'm', 'i', 'x', 0 }; - static id3_ucs4_t const genre_cover[] = { 'C', 'o', 'v', 'e', 'r', 0 }; - unsigned long number; - - if (string == 0 || *string == 0) - return id3_ucs4_empty; - - if (string[0] == 'R' && string[1] == 'X' && string[2] == 0) - return genre_remix; - if (string[0] == 'C' && string[1] == 'R' && string[2] == 0) - return genre_cover; - - for (ptr = (id3_ucs4_t *)string; *ptr; ++ptr) { - if (*ptr < '0' || *ptr > '9') - return string; - } - - number = id3_ucs4_getnumber(string); - - return (number < NGENRES) ? genre_table[number] : string; -} - -/* - * NAME: translate() - * DESCRIPTION: return a canonicalized character for testing genre equivalence - */ -static -id3_ucs4_t translate(id3_ucs4_t ch) -{ - if (ch) { - if (ch >= 'A' && ch <= 'Z') - ch += 'a' - 'A'; - - if (ch < 'a' || ch > 'z') - ch = ID3_UCS4_REPLACEMENTCHAR; - } - - return ch; -} - -/* - * NAME: compare() - * DESCRIPTION: test two ucs4 genre strings for equivalence - */ -static -int compare(id3_ucs4_t const *str1, id3_ucs4_t const *str2) -{ - id3_ucs4_t c1, c2; - - if (str1 == str2) - return 1; - - do { - do - c1 = translate(*str1++); - while (c1 == ID3_UCS4_REPLACEMENTCHAR); - - do - c2 = translate(*str2++); - while (c2 == ID3_UCS4_REPLACEMENTCHAR); - } - while (c1 && c1 == c2); - - return c1 == c2; -} - -/* - * NAME: genre->number() - * DESCRIPTION: translate an ID3v2 genre name/number to its ID3v1 index number - */ -int id3_genre_number(id3_ucs4_t const *string) -{ - id3_ucs4_t const *ptr; - int i; - - if (string == 0 || *string == 0) - return -1; - - for (ptr = string; *ptr; ++ptr) { - if (*ptr < '0' || *ptr > '9') - break; - } - - if (*ptr == 0) { - unsigned long number; - - number = id3_ucs4_getnumber(string); - - return (number <= 0xff) ? number : -1; - } - - for (i = 0; i < NGENRES; ++i) { - if (compare(string, genre_table[i])) - return i; - } - - /* no equivalent */ - - return -1; -} diff --git a/src/libid3tag/genre.dat b/src/libid3tag/genre.dat deleted file mode 100644 index 17acab5..0000000 --- a/src/libid3tag/genre.dat +++ /dev/null @@ -1,480 +0,0 @@ -/* Automatically generated from genre.dat.in */ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Id: genre.dat.in,v 1.7 2004/01/23 09:41:32 rob Exp - */ - -/* - * These are the ID3 genre names, taken as a combination of names from ID3v1 - * (listed in Appendix A of the ID3 tag version 2.4.0 informal standard) and - * the extensions made by Winamp as of version 2.80. - */ - -/* ID3v1 names (0-79) */ - -static id3_ucs4_t const genre_BLUES[] = - { 'B', 'l', 'u', 'e', 's', 0 }; -static id3_ucs4_t const genre_CLASSIC_ROCK[] = - { 'C', 'l', 'a', 's', 's', 'i', 'c', ' ', 'R', 'o', 'c', 'k', 0 }; -static id3_ucs4_t const genre_COUNTRY[] = - { 'C', 'o', 'u', 'n', 't', 'r', 'y', 0 }; -static id3_ucs4_t const genre_DANCE[] = - { 'D', 'a', 'n', 'c', 'e', 0 }; -static id3_ucs4_t const genre_DISCO[] = - { 'D', 'i', 's', 'c', 'o', 0 }; -static id3_ucs4_t const genre_FUNK[] = - { 'F', 'u', 'n', 'k', 0 }; -static id3_ucs4_t const genre_GRUNGE[] = - { 'G', 'r', 'u', 'n', 'g', 'e', 0 }; -static id3_ucs4_t const genre_HIP_HOP[] = - { 'H', 'i', 'p', '-', 'H', 'o', 'p', 0 }; -static id3_ucs4_t const genre_JAZZ[] = - { 'J', 'a', 'z', 'z', 0 }; -static id3_ucs4_t const genre_METAL[] = - { 'M', 'e', 't', 'a', 'l', 0 }; -static id3_ucs4_t const genre_NEW_AGE[] = - { 'N', 'e', 'w', ' ', 'A', 'g', 'e', 0 }; -static id3_ucs4_t const genre_OLDIES[] = - { 'O', 'l', 'd', 'i', 'e', 's', 0 }; -static id3_ucs4_t const genre_OTHER[] = - { 'O', 't', 'h', 'e', 'r', 0 }; -static id3_ucs4_t const genre_POP[] = - { 'P', 'o', 'p', 0 }; -static id3_ucs4_t const genre_R_B[] = - { 'R', '&', 'B', 0 }; -static id3_ucs4_t const genre_RAP[] = - { 'R', 'a', 'p', 0 }; -static id3_ucs4_t const genre_REGGAE[] = - { 'R', 'e', 'g', 'g', 'a', 'e', 0 }; -static id3_ucs4_t const genre_ROCK[] = - { 'R', 'o', 'c', 'k', 0 }; -static id3_ucs4_t const genre_TECHNO[] = - { 'T', 'e', 'c', 'h', 'n', 'o', 0 }; -static id3_ucs4_t const genre_INDUSTRIAL[] = - { 'I', 'n', 'd', 'u', 's', 't', 'r', 'i', 'a', 'l', 0 }; -static id3_ucs4_t const genre_ALTERNATIVE[] = - { 'A', 'l', 't', 'e', 'r', 'n', 'a', 't', 'i', 'v', 'e', 0 }; -static id3_ucs4_t const genre_SKA[] = - { 'S', 'k', 'a', 0 }; -static id3_ucs4_t const genre_DEATH_METAL[] = - { 'D', 'e', 'a', 't', 'h', ' ', 'M', 'e', 't', 'a', 'l', 0 }; -static id3_ucs4_t const genre_PRANKS[] = - { 'P', 'r', 'a', 'n', 'k', 's', 0 }; -static id3_ucs4_t const genre_SOUNDTRACK[] = - { 'S', 'o', 'u', 'n', 'd', 't', 'r', 'a', 'c', 'k', 0 }; -static id3_ucs4_t const genre_EURO_TECHNO[] = - { 'E', 'u', 'r', 'o', '-', 'T', 'e', 'c', 'h', 'n', 'o', 0 }; -static id3_ucs4_t const genre_AMBIENT[] = - { 'A', 'm', 'b', 'i', 'e', 'n', 't', 0 }; -static id3_ucs4_t const genre_TRIP_HOP[] = - { 'T', 'r', 'i', 'p', '-', 'H', 'o', 'p', 0 }; -static id3_ucs4_t const genre_VOCAL[] = - { 'V', 'o', 'c', 'a', 'l', 0 }; -static id3_ucs4_t const genre_JAZZ_FUNK[] = - { 'J', 'a', 'z', 'z', '+', 'F', 'u', 'n', 'k', 0 }; -static id3_ucs4_t const genre_FUSION[] = - { 'F', 'u', 's', 'i', 'o', 'n', 0 }; -static id3_ucs4_t const genre_TRANCE[] = - { 'T', 'r', 'a', 'n', 'c', 'e', 0 }; -static id3_ucs4_t const genre_CLASSICAL[] = - { 'C', 'l', 'a', 's', 's', 'i', 'c', 'a', 'l', 0 }; -static id3_ucs4_t const genre_INSTRUMENTAL[] = - { 'I', 'n', 's', 't', 'r', 'u', 'm', 'e', 'n', 't', 'a', 'l', 0 }; -static id3_ucs4_t const genre_ACID[] = - { 'A', 'c', 'i', 'd', 0 }; -static id3_ucs4_t const genre_HOUSE[] = - { 'H', 'o', 'u', 's', 'e', 0 }; -static id3_ucs4_t const genre_GAME[] = - { 'G', 'a', 'm', 'e', 0 }; -static id3_ucs4_t const genre_SOUND_CLIP[] = - { 'S', 'o', 'u', 'n', 'd', ' ', 'C', 'l', 'i', 'p', 0 }; -static id3_ucs4_t const genre_GOSPEL[] = - { 'G', 'o', 's', 'p', 'e', 'l', 0 }; -static id3_ucs4_t const genre_NOISE[] = - { 'N', 'o', 'i', 's', 'e', 0 }; -static id3_ucs4_t const genre_ALTERNROCK[] = - { 'A', 'l', 't', 'e', 'r', 'n', 'R', 'o', 'c', 'k', 0 }; -static id3_ucs4_t const genre_BASS[] = - { 'B', 'a', 's', 's', 0 }; -static id3_ucs4_t const genre_SOUL[] = - { 'S', 'o', 'u', 'l', 0 }; -static id3_ucs4_t const genre_PUNK[] = - { 'P', 'u', 'n', 'k', 0 }; -static id3_ucs4_t const genre_SPACE[] = - { 'S', 'p', 'a', 'c', 'e', 0 }; -static id3_ucs4_t const genre_MEDITATIVE[] = - { 'M', 'e', 'd', 'i', 't', 'a', 't', 'i', 'v', 'e', 0 }; -static id3_ucs4_t const genre_INSTRUMENTAL_POP[] = - { 'I', 'n', 's', 't', 'r', 'u', 'm', 'e', 'n', 't', 'a', 'l', ' ', 'P', 'o', 'p', 0 }; -static id3_ucs4_t const genre_INSTRUMENTAL_ROCK[] = - { 'I', 'n', 's', 't', 'r', 'u', 'm', 'e', 'n', 't', 'a', 'l', ' ', 'R', 'o', 'c', 'k', 0 }; -static id3_ucs4_t const genre_ETHNIC[] = - { 'E', 't', 'h', 'n', 'i', 'c', 0 }; -static id3_ucs4_t const genre_GOTHIC[] = - { 'G', 'o', 't', 'h', 'i', 'c', 0 }; -static id3_ucs4_t const genre_DARKWAVE[] = - { 'D', 'a', 'r', 'k', 'w', 'a', 'v', 'e', 0 }; -static id3_ucs4_t const genre_TECHNO_INDUSTRIAL[] = - { 'T', 'e', 'c', 'h', 'n', 'o', '-', 'I', 'n', 'd', 'u', 's', 't', 'r', 'i', 'a', 'l', 0 }; -static id3_ucs4_t const genre_ELECTRONIC[] = - { 'E', 'l', 'e', 'c', 't', 'r', 'o', 'n', 'i', 'c', 0 }; -static id3_ucs4_t const genre_POP_FOLK[] = - { 'P', 'o', 'p', '-', 'F', 'o', 'l', 'k', 0 }; -static id3_ucs4_t const genre_EURODANCE[] = - { 'E', 'u', 'r', 'o', 'd', 'a', 'n', 'c', 'e', 0 }; -static id3_ucs4_t const genre_DREAM[] = - { 'D', 'r', 'e', 'a', 'm', 0 }; -static id3_ucs4_t const genre_SOUTHERN_ROCK[] = - { 'S', 'o', 'u', 't', 'h', 'e', 'r', 'n', ' ', 'R', 'o', 'c', 'k', 0 }; -static id3_ucs4_t const genre_COMEDY[] = - { 'C', 'o', 'm', 'e', 'd', 'y', 0 }; -static id3_ucs4_t const genre_CULT[] = - { 'C', 'u', 'l', 't', 0 }; -static id3_ucs4_t const genre_GANGSTA[] = - { 'G', 'a', 'n', 'g', 's', 't', 'a', 0 }; -static id3_ucs4_t const genre_TOP_40[] = - { 'T', 'o', 'p', ' ', '4', '0', 0 }; -static id3_ucs4_t const genre_CHRISTIAN_RAP[] = - { 'C', 'h', 'r', 'i', 's', 't', 'i', 'a', 'n', ' ', 'R', 'a', 'p', 0 }; -static id3_ucs4_t const genre_POP_FUNK[] = - { 'P', 'o', 'p', '/', 'F', 'u', 'n', 'k', 0 }; -static id3_ucs4_t const genre_JUNGLE[] = - { 'J', 'u', 'n', 'g', 'l', 'e', 0 }; -static id3_ucs4_t const genre_NATIVE_AMERICAN[] = - { 'N', 'a', 't', 'i', 'v', 'e', ' ', 'A', 'm', 'e', 'r', 'i', 'c', 'a', 'n', 0 }; -static id3_ucs4_t const genre_CABARET[] = - { 'C', 'a', 'b', 'a', 'r', 'e', 't', 0 }; -static id3_ucs4_t const genre_NEW_WAVE[] = - { 'N', 'e', 'w', ' ', 'W', 'a', 'v', 'e', 0 }; -static id3_ucs4_t const genre_PSYCHEDELIC[] = - { 'P', 's', 'y', 'c', 'h', 'e', 'd', 'e', 'l', 'i', 'c', 0 }; -static id3_ucs4_t const genre_RAVE[] = - { 'R', 'a', 'v', 'e', 0 }; -static id3_ucs4_t const genre_SHOWTUNES[] = - { 'S', 'h', 'o', 'w', 't', 'u', 'n', 'e', 's', 0 }; -static id3_ucs4_t const genre_TRAILER[] = - { 'T', 'r', 'a', 'i', 'l', 'e', 'r', 0 }; -static id3_ucs4_t const genre_LO_FI[] = - { 'L', 'o', '-', 'F', 'i', 0 }; -static id3_ucs4_t const genre_TRIBAL[] = - { 'T', 'r', 'i', 'b', 'a', 'l', 0 }; -static id3_ucs4_t const genre_ACID_PUNK[] = - { 'A', 'c', 'i', 'd', ' ', 'P', 'u', 'n', 'k', 0 }; -static id3_ucs4_t const genre_ACID_JAZZ[] = - { 'A', 'c', 'i', 'd', ' ', 'J', 'a', 'z', 'z', 0 }; -static id3_ucs4_t const genre_POLKA[] = - { 'P', 'o', 'l', 'k', 'a', 0 }; -static id3_ucs4_t const genre_RETRO[] = - { 'R', 'e', 't', 'r', 'o', 0 }; -static id3_ucs4_t const genre_MUSICAL[] = - { 'M', 'u', 's', 'i', 'c', 'a', 'l', 0 }; -static id3_ucs4_t const genre_ROCK___ROLL[] = - { 'R', 'o', 'c', 'k', ' ', '&', ' ', 'R', 'o', 'l', 'l', 0 }; -static id3_ucs4_t const genre_HARD_ROCK[] = - { 'H', 'a', 'r', 'd', ' ', 'R', 'o', 'c', 'k', 0 }; - -/* Winamp extensions (80-147) */ - -static id3_ucs4_t const genre_FOLK[] = - { 'F', 'o', 'l', 'k', 0 }; -static id3_ucs4_t const genre_FOLK_ROCK[] = - { 'F', 'o', 'l', 'k', '/', 'R', 'o', 'c', 'k', 0 }; -static id3_ucs4_t const genre_NATIONAL_FOLK[] = - { 'N', 'a', 't', 'i', 'o', 'n', 'a', 'l', ' ', 'F', 'o', 'l', 'k', 0 }; -static id3_ucs4_t const genre_SWING[] = - { 'S', 'w', 'i', 'n', 'g', 0 }; -static id3_ucs4_t const genre_FAST_FUSION[] = - { 'F', 'a', 's', 't', '-', 'F', 'u', 's', 'i', 'o', 'n', 0 }; -static id3_ucs4_t const genre_BEBOB[] = - { 'B', 'e', 'b', 'o', 'b', 0 }; -static id3_ucs4_t const genre_LATIN[] = - { 'L', 'a', 't', 'i', 'n', 0 }; -static id3_ucs4_t const genre_REVIVAL[] = - { 'R', 'e', 'v', 'i', 'v', 'a', 'l', 0 }; -static id3_ucs4_t const genre_CELTIC[] = - { 'C', 'e', 'l', 't', 'i', 'c', 0 }; -static id3_ucs4_t const genre_BLUEGRASS[] = - { 'B', 'l', 'u', 'e', 'g', 'r', 'a', 's', 's', 0 }; -static id3_ucs4_t const genre_AVANTGARDE[] = - { 'A', 'v', 'a', 'n', 't', 'g', 'a', 'r', 'd', 'e', 0 }; -static id3_ucs4_t const genre_GOTHIC_ROCK[] = - { 'G', 'o', 't', 'h', 'i', 'c', ' ', 'R', 'o', 'c', 'k', 0 }; -static id3_ucs4_t const genre_PROGRESSIVE_ROCK[] = - { 'P', 'r', 'o', 'g', 'r', 'e', 's', 's', 'i', 'v', 'e', ' ', 'R', 'o', 'c', 'k', 0 }; -static id3_ucs4_t const genre_PSYCHEDELIC_ROCK[] = - { 'P', 's', 'y', 'c', 'h', 'e', 'd', 'e', 'l', 'i', 'c', ' ', 'R', 'o', 'c', 'k', 0 }; -static id3_ucs4_t const genre_SYMPHONIC_ROCK[] = - { 'S', 'y', 'm', 'p', 'h', 'o', 'n', 'i', 'c', ' ', 'R', 'o', 'c', 'k', 0 }; -static id3_ucs4_t const genre_SLOW_ROCK[] = - { 'S', 'l', 'o', 'w', ' ', 'R', 'o', 'c', 'k', 0 }; -static id3_ucs4_t const genre_BIG_BAND[] = - { 'B', 'i', 'g', ' ', 'B', 'a', 'n', 'd', 0 }; -static id3_ucs4_t const genre_CHORUS[] = - { 'C', 'h', 'o', 'r', 'u', 's', 0 }; -static id3_ucs4_t const genre_EASY_LISTENING[] = - { 'E', 'a', 's', 'y', ' ', 'L', 'i', 's', 't', 'e', 'n', 'i', 'n', 'g', 0 }; -static id3_ucs4_t const genre_ACOUSTIC[] = - { 'A', 'c', 'o', 'u', 's', 't', 'i', 'c', 0 }; -static id3_ucs4_t const genre_HUMOUR[] = - { 'H', 'u', 'm', 'o', 'u', 'r', 0 }; -static id3_ucs4_t const genre_SPEECH[] = - { 'S', 'p', 'e', 'e', 'c', 'h', 0 }; -static id3_ucs4_t const genre_CHANSON[] = - { 'C', 'h', 'a', 'n', 's', 'o', 'n', 0 }; -static id3_ucs4_t const genre_OPERA[] = - { 'O', 'p', 'e', 'r', 'a', 0 }; -static id3_ucs4_t const genre_CHAMBER_MUSIC[] = - { 'C', 'h', 'a', 'm', 'b', 'e', 'r', ' ', 'M', 'u', 's', 'i', 'c', 0 }; -static id3_ucs4_t const genre_SONATA[] = - { 'S', 'o', 'n', 'a', 't', 'a', 0 }; -static id3_ucs4_t const genre_SYMPHONY[] = - { 'S', 'y', 'm', 'p', 'h', 'o', 'n', 'y', 0 }; -static id3_ucs4_t const genre_BOOTY_BASS[] = - { 'B', 'o', 'o', 't', 'y', ' ', 'B', 'a', 's', 's', 0 }; -static id3_ucs4_t const genre_PRIMUS[] = - { 'P', 'r', 'i', 'm', 'u', 's', 0 }; -static id3_ucs4_t const genre_PORN_GROOVE[] = - { 'P', 'o', 'r', 'n', ' ', 'G', 'r', 'o', 'o', 'v', 'e', 0 }; -static id3_ucs4_t const genre_SATIRE[] = - { 'S', 'a', 't', 'i', 'r', 'e', 0 }; -static id3_ucs4_t const genre_SLOW_JAM[] = - { 'S', 'l', 'o', 'w', ' ', 'J', 'a', 'm', 0 }; -static id3_ucs4_t const genre_CLUB[] = - { 'C', 'l', 'u', 'b', 0 }; -static id3_ucs4_t const genre_TANGO[] = - { 'T', 'a', 'n', 'g', 'o', 0 }; -static id3_ucs4_t const genre_SAMBA[] = - { 'S', 'a', 'm', 'b', 'a', 0 }; -static id3_ucs4_t const genre_FOLKLORE[] = - { 'F', 'o', 'l', 'k', 'l', 'o', 'r', 'e', 0 }; -static id3_ucs4_t const genre_BALLAD[] = - { 'B', 'a', 'l', 'l', 'a', 'd', 0 }; -static id3_ucs4_t const genre_POWER_BALLAD[] = - { 'P', 'o', 'w', 'e', 'r', ' ', 'B', 'a', 'l', 'l', 'a', 'd', 0 }; -static id3_ucs4_t const genre_RHYTHMIC_SOUL[] = - { 'R', 'h', 'y', 't', 'h', 'm', 'i', 'c', ' ', 'S', 'o', 'u', 'l', 0 }; -static id3_ucs4_t const genre_FREESTYLE[] = - { 'F', 'r', 'e', 'e', 's', 't', 'y', 'l', 'e', 0 }; -static id3_ucs4_t const genre_DUET[] = - { 'D', 'u', 'e', 't', 0 }; -static id3_ucs4_t const genre_PUNK_ROCK[] = - { 'P', 'u', 'n', 'k', ' ', 'R', 'o', 'c', 'k', 0 }; -static id3_ucs4_t const genre_DRUM_SOLO[] = - { 'D', 'r', 'u', 'm', ' ', 'S', 'o', 'l', 'o', 0 }; -static id3_ucs4_t const genre_A_CAPPELLA[] = - { 'A', ' ', 'C', 'a', 'p', 'p', 'e', 'l', 'l', 'a', 0 }; -static id3_ucs4_t const genre_EURO_HOUSE[] = - { 'E', 'u', 'r', 'o', '-', 'H', 'o', 'u', 's', 'e', 0 }; -static id3_ucs4_t const genre_DANCE_HALL[] = - { 'D', 'a', 'n', 'c', 'e', ' ', 'H', 'a', 'l', 'l', 0 }; -static id3_ucs4_t const genre_GOA[] = - { 'G', 'o', 'a', 0 }; -static id3_ucs4_t const genre_DRUM___BASS[] = - { 'D', 'r', 'u', 'm', ' ', '&', ' ', 'B', 'a', 's', 's', 0 }; -static id3_ucs4_t const genre_CLUB_HOUSE[] = - { 'C', 'l', 'u', 'b', '-', 'H', 'o', 'u', 's', 'e', 0 }; -static id3_ucs4_t const genre_HARDCORE[] = - { 'H', 'a', 'r', 'd', 'c', 'o', 'r', 'e', 0 }; -static id3_ucs4_t const genre_TERROR[] = - { 'T', 'e', 'r', 'r', 'o', 'r', 0 }; -static id3_ucs4_t const genre_INDIE[] = - { 'I', 'n', 'd', 'i', 'e', 0 }; -static id3_ucs4_t const genre_BRITPOP[] = - { 'B', 'r', 'i', 't', 'P', 'o', 'p', 0 }; -static id3_ucs4_t const genre_NEGERPUNK[] = - { 'N', 'e', 'g', 'e', 'r', 'p', 'u', 'n', 'k', 0 }; -static id3_ucs4_t const genre_POLSK_PUNK[] = - { 'P', 'o', 'l', 's', 'k', ' ', 'P', 'u', 'n', 'k', 0 }; -static id3_ucs4_t const genre_BEAT[] = - { 'B', 'e', 'a', 't', 0 }; -static id3_ucs4_t const genre_CHRISTIAN_GANGSTA_RAP[] = - { 'C', 'h', 'r', 'i', 's', 't', 'i', 'a', 'n', ' ', 'G', 'a', 'n', 'g', 's', 't', 'a', ' ', 'R', 'a', 'p', 0 }; -static id3_ucs4_t const genre_HEAVY_METAL[] = - { 'H', 'e', 'a', 'v', 'y', ' ', 'M', 'e', 't', 'a', 'l', 0 }; -static id3_ucs4_t const genre_BLACK_METAL[] = - { 'B', 'l', 'a', 'c', 'k', ' ', 'M', 'e', 't', 'a', 'l', 0 }; -static id3_ucs4_t const genre_CROSSOVER[] = - { 'C', 'r', 'o', 's', 's', 'o', 'v', 'e', 'r', 0 }; -static id3_ucs4_t const genre_CONTEMPORARY_CHRISTIAN[] = - { 'C', 'o', 'n', 't', 'e', 'm', 'p', 'o', 'r', 'a', 'r', 'y', ' ', 'C', 'h', 'r', 'i', 's', 't', 'i', 'a', 'n', 0 }; -static id3_ucs4_t const genre_CHRISTIAN_ROCK[] = - { 'C', 'h', 'r', 'i', 's', 't', 'i', 'a', 'n', ' ', 'R', 'o', 'c', 'k', 0 }; -static id3_ucs4_t const genre_MERENGUE[] = - { 'M', 'e', 'r', 'e', 'n', 'g', 'u', 'e', 0 }; -static id3_ucs4_t const genre_SALSA[] = - { 'S', 'a', 'l', 's', 'a', 0 }; -static id3_ucs4_t const genre_THRASH_METAL[] = - { 'T', 'h', 'r', 'a', 's', 'h', ' ', 'M', 'e', 't', 'a', 'l', 0 }; -static id3_ucs4_t const genre_ANIME[] = - { 'A', 'n', 'i', 'm', 'e', 0 }; -static id3_ucs4_t const genre_JPOP[] = - { 'J', 'P', 'o', 'p', 0 }; -static id3_ucs4_t const genre_SYNTHPOP[] = - { 'S', 'y', 'n', 't', 'h', 'p', 'o', 'p', 0 }; - -static id3_ucs4_t const *const genre_table[] = { - genre_BLUES, - genre_CLASSIC_ROCK, - genre_COUNTRY, - genre_DANCE, - genre_DISCO, - genre_FUNK, - genre_GRUNGE, - genre_HIP_HOP, - genre_JAZZ, - genre_METAL, - genre_NEW_AGE, - genre_OLDIES, - genre_OTHER, - genre_POP, - genre_R_B, - genre_RAP, - genre_REGGAE, - genre_ROCK, - genre_TECHNO, - genre_INDUSTRIAL, - genre_ALTERNATIVE, - genre_SKA, - genre_DEATH_METAL, - genre_PRANKS, - genre_SOUNDTRACK, - genre_EURO_TECHNO, - genre_AMBIENT, - genre_TRIP_HOP, - genre_VOCAL, - genre_JAZZ_FUNK, - genre_FUSION, - genre_TRANCE, - genre_CLASSICAL, - genre_INSTRUMENTAL, - genre_ACID, - genre_HOUSE, - genre_GAME, - genre_SOUND_CLIP, - genre_GOSPEL, - genre_NOISE, - genre_ALTERNROCK, - genre_BASS, - genre_SOUL, - genre_PUNK, - genre_SPACE, - genre_MEDITATIVE, - genre_INSTRUMENTAL_POP, - genre_INSTRUMENTAL_ROCK, - genre_ETHNIC, - genre_GOTHIC, - genre_DARKWAVE, - genre_TECHNO_INDUSTRIAL, - genre_ELECTRONIC, - genre_POP_FOLK, - genre_EURODANCE, - genre_DREAM, - genre_SOUTHERN_ROCK, - genre_COMEDY, - genre_CULT, - genre_GANGSTA, - genre_TOP_40, - genre_CHRISTIAN_RAP, - genre_POP_FUNK, - genre_JUNGLE, - genre_NATIVE_AMERICAN, - genre_CABARET, - genre_NEW_WAVE, - genre_PSYCHEDELIC, - genre_RAVE, - genre_SHOWTUNES, - genre_TRAILER, - genre_LO_FI, - genre_TRIBAL, - genre_ACID_PUNK, - genre_ACID_JAZZ, - genre_POLKA, - genre_RETRO, - genre_MUSICAL, - genre_ROCK___ROLL, - genre_HARD_ROCK, - genre_FOLK, - genre_FOLK_ROCK, - genre_NATIONAL_FOLK, - genre_SWING, - genre_FAST_FUSION, - genre_BEBOB, - genre_LATIN, - genre_REVIVAL, - genre_CELTIC, - genre_BLUEGRASS, - genre_AVANTGARDE, - genre_GOTHIC_ROCK, - genre_PROGRESSIVE_ROCK, - genre_PSYCHEDELIC_ROCK, - genre_SYMPHONIC_ROCK, - genre_SLOW_ROCK, - genre_BIG_BAND, - genre_CHORUS, - genre_EASY_LISTENING, - genre_ACOUSTIC, - genre_HUMOUR, - genre_SPEECH, - genre_CHANSON, - genre_OPERA, - genre_CHAMBER_MUSIC, - genre_SONATA, - genre_SYMPHONY, - genre_BOOTY_BASS, - genre_PRIMUS, - genre_PORN_GROOVE, - genre_SATIRE, - genre_SLOW_JAM, - genre_CLUB, - genre_TANGO, - genre_SAMBA, - genre_FOLKLORE, - genre_BALLAD, - genre_POWER_BALLAD, - genre_RHYTHMIC_SOUL, - genre_FREESTYLE, - genre_DUET, - genre_PUNK_ROCK, - genre_DRUM_SOLO, - genre_A_CAPPELLA, - genre_EURO_HOUSE, - genre_DANCE_HALL, - genre_GOA, - genre_DRUM___BASS, - genre_CLUB_HOUSE, - genre_HARDCORE, - genre_TERROR, - genre_INDIE, - genre_BRITPOP, - genre_NEGERPUNK, - genre_POLSK_PUNK, - genre_BEAT, - genre_CHRISTIAN_GANGSTA_RAP, - genre_HEAVY_METAL, - genre_BLACK_METAL, - genre_CROSSOVER, - genre_CONTEMPORARY_CHRISTIAN, - genre_CHRISTIAN_ROCK, - genre_MERENGUE, - genre_SALSA, - genre_THRASH_METAL, - genre_ANIME, - genre_JPOP, - genre_SYNTHPOP -}; diff --git a/src/libid3tag/genre.dat.in b/src/libid3tag/genre.dat.in deleted file mode 100644 index 872de40..0000000 --- a/src/libid3tag/genre.dat.in +++ /dev/null @@ -1,180 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: genre.dat.in,v 1.7 2004/01/23 09:41:32 rob Exp $ - */ - -/* - * These are the ID3 genre names, taken as a combination of names from ID3v1 - * (listed in Appendix A of the ID3 tag version 2.4.0 informal standard) and - * the extensions made by Winamp as of version 2.80. - */ - -/* ID3v1 names (0-79) */ - -Blues -Classic Rock -Country -Dance -Disco -Funk -Grunge -Hip-Hop -Jazz -Metal -New Age -Oldies -Other -Pop -R&B -Rap -Reggae -Rock -Techno -Industrial -Alternative -Ska -Death Metal -Pranks -Soundtrack -Euro-Techno -Ambient -Trip-Hop -Vocal -Jazz+Funk -Fusion -Trance -Classical -Instrumental -Acid -House -Game -Sound Clip -Gospel -Noise -AlternRock -Bass -Soul -Punk -Space -Meditative -Instrumental Pop -Instrumental Rock -Ethnic -Gothic -Darkwave -Techno-Industrial -Electronic -Pop-Folk -Eurodance -Dream -Southern Rock -Comedy -Cult -Gangsta -Top 40 -Christian Rap -Pop/Funk -Jungle -Native American -Cabaret -New Wave -Psychedelic -Rave -Showtunes -Trailer -Lo-Fi -Tribal -Acid Punk -Acid Jazz -Polka -Retro -Musical -Rock & Roll -Hard Rock - -/* Winamp extensions (80-147) */ - -Folk -Folk/Rock -National Folk -Swing -Fast-Fusion -Bebob -Latin -Revival -Celtic -Bluegrass -Avantgarde -Gothic Rock -Progressive Rock -Psychedelic Rock -Symphonic Rock -Slow Rock -Big Band -Chorus -Easy Listening -Acoustic -Humour -Speech -Chanson -Opera -Chamber Music -Sonata -Symphony -Booty Bass -Primus -Porn Groove -Satire -Slow Jam -Club -Tango -Samba -Folklore -Ballad -Power Ballad -Rhythmic Soul -Freestyle -Duet -Punk Rock -Drum Solo -A Cappella -Euro-House -Dance Hall -Goa -Drum & Bass -Club-House -Hardcore -Terror -Indie -BritPop -Negerpunk -Polsk Punk -Beat -Christian Gangsta Rap -Heavy Metal -Black Metal -Crossover -Contemporary Christian -Christian Rock -Merengue -Salsa -Thrash Metal -Anime -JPop -Synthpop diff --git a/src/libid3tag/genre.dat.sed b/src/libid3tag/genre.dat.sed deleted file mode 100644 index b8be6c5..0000000 --- a/src/libid3tag/genre.dat.sed +++ /dev/null @@ -1,54 +0,0 @@ -# -# libid3tag - ID3 tag manipulation library -# Copyright (C) 2000-2004 Underbit Technologies, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# $Id: genre.dat.sed,v 1.10 2004/01/23 09:41:32 rob Exp $ -# - -1i\ -/* Automatically generated from genre.dat.in */ - -# generate an array from a string -/^[A-Za-z]/{ -H -y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ -s/[^A-Z0-9]/_/g -s/.*/static id3_ucs4_t const genre_&[] =/p -g -s/.*\n// -s/./'&', /g -s/.*/ { &0 };/ -} - -# write the final table of arrays -${ -p -i\ -\ -static id3_ucs4_t const *const genre_table[] = { -g -s/^\(\n\)\(.*\)$/\2\1/ -y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ -s/[^A-Z0-9\n]/_/g -s/\([^\n]*\)\(\n\)/ genre_\1,\2/g -s/,\n$// -a\ -}; -} - -# print the pattern space (assumes -n) -p diff --git a/src/libid3tag/genre.h b/src/libid3tag/genre.h deleted file mode 100644 index 56d538a..0000000 --- a/src/libid3tag/genre.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: genre.h,v 1.6 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_GENRE_H -# define LIBID3TAG_GENRE_H - -# define ID3_GENRE_OTHER 12 - -# endif diff --git a/src/libid3tag/global.h b/src/libid3tag/global.h deleted file mode 100644 index 377a5e6..0000000 --- a/src/libid3tag/global.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: global.h,v 1.9 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_GLOBAL_H -# define LIBID3TAG_GLOBAL_H - -/* conditional debugging */ - -# if defined(DEBUG) && defined(NDEBUG) -# error "cannot define both DEBUG and NDEBUG" -# endif - -# if defined(DEBUG) -# include <stdio.h> -# include "debug.h" -# define malloc(sz) id3_debug_malloc(sz, __FILE__, __LINE__) -# define calloc(n, sz) id3_debug_calloc(n, sz, __FILE__, __LINE__) -# define realloc(ptr, sz) id3_debug_realloc(ptr, sz, __FILE__, __LINE__) -# define free(ptr) id3_debug_free(ptr, __FILE__, __LINE__) -# define release(ptr) id3_debug_release(ptr, __FILE__, __LINE__) -# else -# define release(ptr) (ptr) -# endif - -/* conditional features */ - -# if !defined(HAVE_ASSERT_H) -# if defined(NDEBUG) -# define assert(x) /* nothing */ -# else -# define assert(x) do { if (!(x)) abort(); } while (0) -# endif -# endif - -# endif diff --git a/src/libid3tag/id3tag.h b/src/libid3tag/id3tag.h deleted file mode 100644 index fc9bbfd..0000000 --- a/src/libid3tag/id3tag.h +++ /dev/null @@ -1,367 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * If you would like to negotiate alternate licensing terms, you may do - * so by contacting: Underbit Technologies, Inc. <info@underbit.com> - * - * $Id: id3tag.h,v 1.17 2004/01/23 23:22:46 rob Exp $ - */ - -# ifndef LIBID3TAG_ID3TAG_H -# define LIBID3TAG_ID3TAG_H - -# ifdef __cplusplus -extern "C" { -# endif - -#include "libaudcore/vfs.h" - -# define ID3_TAG_VERSION 0x0400 -# define ID3_TAG_VERSION_MAJOR(x) (((x) >> 8) & 0xff) -# define ID3_TAG_VERSION_MINOR(x) (((x) >> 0) & 0xff) - -typedef unsigned char id3_byte_t; -typedef unsigned long id3_length_t; - -typedef unsigned long id3_ucs4_t; - -typedef unsigned char id3_latin1_t; -typedef unsigned short id3_utf16_t; -typedef signed char id3_utf8_t; - -struct id3_tag { - unsigned int refcount; - unsigned int version; - int flags; - int extendedflags; - int restrictions; - int options; - unsigned int nframes; - struct id3_frame **frames; - id3_length_t paddedsize; -}; - -# define ID3_TAG_QUERYSIZE 10 - -/* ID3v1 field frames */ - -# define ID3_FRAME_TITLE "TIT2" -# define ID3_FRAME_ARTIST "TPE1" -# define ID3_FRAME_ALBUM "TALB" -# define ID3_FRAME_TRACK "TRCK" -# define ID3_FRAME_YEAR "TDRC" -# define ID3_FRAME_GENRE "TCON" -# define ID3_FRAME_COMMENT "COMM" - -/* special frames */ - -# define ID3_FRAME_OBSOLETE "ZOBS" /* with apologies to the French */ - -/* tag flags */ - -enum { - ID3_TAG_FLAG_UNSYNCHRONISATION = 0x80, - ID3_TAG_FLAG_EXTENDEDHEADER = 0x40, - ID3_TAG_FLAG_EXPERIMENTALINDICATOR = 0x20, - ID3_TAG_FLAG_FOOTERPRESENT = 0x10, - - ID3_TAG_FLAG_KNOWNFLAGS = 0xf0 -}; - -/* tag extended flags */ - -enum { - ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE = 0x40, - ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT = 0x20, - ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS = 0x10, - - ID3_TAG_EXTENDEDFLAG_KNOWNFLAGS = 0x70 -}; - -/* tag restrictions */ - -enum { - ID3_TAG_RESTRICTION_TAGSIZE_MASK = 0xc0, - ID3_TAG_RESTRICTION_TAGSIZE_128_FRAMES_1_MB = 0x00, - ID3_TAG_RESTRICTION_TAGSIZE_64_FRAMES_128_KB = 0x40, - ID3_TAG_RESTRICTION_TAGSIZE_32_FRAMES_40_KB = 0x80, - ID3_TAG_RESTRICTION_TAGSIZE_32_FRAMES_4_KB = 0xc0 -}; - -enum { - ID3_TAG_RESTRICTION_TEXTENCODING_MASK = 0x20, - ID3_TAG_RESTRICTION_TEXTENCODING_NONE = 0x00, - ID3_TAG_RESTRICTION_TEXTENCODING_LATIN1_UTF8 = 0x20 -}; - -enum { - ID3_TAG_RESTRICTION_TEXTSIZE_MASK = 0x18, - ID3_TAG_RESTRICTION_TEXTSIZE_NONE = 0x00, - ID3_TAG_RESTRICTION_TEXTSIZE_1024_CHARS = 0x08, - ID3_TAG_RESTRICTION_TEXTSIZE_128_CHARS = 0x10, - ID3_TAG_RESTRICTION_TEXTSIZE_30_CHARS = 0x18 -}; - -enum { - ID3_TAG_RESTRICTION_IMAGEENCODING_MASK = 0x04, - ID3_TAG_RESTRICTION_IMAGEENCODING_NONE = 0x00, - ID3_TAG_RESTRICTION_IMAGEENCODING_PNG_JPEG = 0x04 -}; - -enum { - ID3_TAG_RESTRICTION_IMAGESIZE_MASK = 0x03, - ID3_TAG_RESTRICTION_IMAGESIZE_NONE = 0x00, - ID3_TAG_RESTRICTION_IMAGESIZE_256_256 = 0x01, - ID3_TAG_RESTRICTION_IMAGESIZE_64_64 = 0x02, - ID3_TAG_RESTRICTION_IMAGESIZE_64_64_EXACT = 0x03 -}; - -/* library options */ - -enum { - ID3_TAG_OPTION_UNSYNCHRONISATION = 0x0001, /* use unsynchronisation */ - ID3_TAG_OPTION_COMPRESSION = 0x0002, /* use compression */ - ID3_TAG_OPTION_CRC = 0x0004, /* use CRC */ - - ID3_TAG_OPTION_APPENDEDTAG = 0x0010, /* tag will be appended */ - ID3_TAG_OPTION_FILEALTERED = 0x0020, /* audio data was altered */ - - ID3_TAG_OPTION_ID3V1 = 0x0100 /* render ID3v1/ID3v1.1 tag */ -}; - -struct id3_frame { - char id[5]; - char const *description; - unsigned int refcount; - int flags; - int group_id; - int encryption_method; - id3_byte_t *encoded; - id3_length_t encoded_length; - id3_length_t decoded_length; - unsigned int nfields; - union id3_field *fields; -}; - -enum { - /* frame status flags */ - ID3_FRAME_FLAG_TAGALTERPRESERVATION = 0x4000, - ID3_FRAME_FLAG_FILEALTERPRESERVATION = 0x2000, - ID3_FRAME_FLAG_READONLY = 0x1000, - - ID3_FRAME_FLAG_STATUSFLAGS = 0xff00, - - /* frame format flags */ - ID3_FRAME_FLAG_GROUPINGIDENTITY = 0x0040, - ID3_FRAME_FLAG_COMPRESSION = 0x0008, - ID3_FRAME_FLAG_ENCRYPTION = 0x0004, - ID3_FRAME_FLAG_UNSYNCHRONISATION = 0x0002, - ID3_FRAME_FLAG_DATALENGTHINDICATOR = 0x0001, - - ID3_FRAME_FLAG_FORMATFLAGS = 0x00ff, - - ID3_FRAME_FLAG_KNOWNFLAGS = 0x704f -}; - -enum id3_field_type { - ID3_FIELD_TYPE_TEXTENCODING, - ID3_FIELD_TYPE_LATIN1, - ID3_FIELD_TYPE_LATIN1FULL, - ID3_FIELD_TYPE_LATIN1LIST, - ID3_FIELD_TYPE_STRING, - ID3_FIELD_TYPE_STRINGFULL, - ID3_FIELD_TYPE_STRINGLIST, - ID3_FIELD_TYPE_LANGUAGE, - ID3_FIELD_TYPE_FRAMEID, - ID3_FIELD_TYPE_DATE, - ID3_FIELD_TYPE_INT8, - ID3_FIELD_TYPE_INT16, - ID3_FIELD_TYPE_INT24, - ID3_FIELD_TYPE_INT32, - ID3_FIELD_TYPE_INT32PLUS, - ID3_FIELD_TYPE_BINARYDATA -}; - -enum id3_field_textencoding { - ID3_FIELD_TEXTENCODING_ISO_8859_1 = 0x00, - ID3_FIELD_TEXTENCODING_UTF_16 = 0x01, - ID3_FIELD_TEXTENCODING_UTF_16BE = 0x02, - ID3_FIELD_TEXTENCODING_UTF_8 = 0x03 -}; - -union id3_field { - enum id3_field_type type; - struct { - enum id3_field_type type; - signed long value; - } number; - struct { - enum id3_field_type type; - id3_latin1_t *ptr; - } latin1; - struct { - enum id3_field_type type; - unsigned int nstrings; - id3_latin1_t **strings; - } latin1list; - struct { - enum id3_field_type type; - id3_ucs4_t *ptr; - } string; - struct { - enum id3_field_type type; - unsigned int nstrings; - id3_ucs4_t **strings; - } stringlist; - struct { - enum id3_field_type type; - char value[9]; - } immediate; - struct { - enum id3_field_type type; - id3_byte_t *data; - id3_length_t length; - } binary; -}; - -/* file interface */ - -enum id3_file_mode { - ID3_FILE_MODE_READONLY = 0, - ID3_FILE_MODE_READWRITE -}; - -struct id3_file *id3_file_open(char const *, enum id3_file_mode); -struct id3_file *id3_file_vfsopen(VFSFile *, enum id3_file_mode); -struct id3_file *id3_file_fdopen(int, enum id3_file_mode); -int id3_file_close(struct id3_file *); - -struct id3_tag *id3_file_tag(struct id3_file const *); - -int id3_file_update(struct id3_file *); - -/* tag interface */ - -struct id3_tag *id3_tag_new(void); -void id3_tag_delete(struct id3_tag *); - -unsigned int id3_tag_version(struct id3_tag const *); - -int id3_tag_options(struct id3_tag *, int, int); -void id3_tag_setlength(struct id3_tag *, id3_length_t); - -void id3_tag_clearframes(struct id3_tag *); - -int id3_tag_attachframe(struct id3_tag *, struct id3_frame *); -int id3_tag_detachframe(struct id3_tag *, struct id3_frame *); - -struct id3_frame *id3_tag_findframe(struct id3_tag const *, - char const *, unsigned int); - -signed long id3_tag_query(id3_byte_t const *, id3_length_t); - -struct id3_tag *id3_tag_parse(id3_byte_t const *, id3_length_t); -id3_length_t id3_tag_render(struct id3_tag const *, id3_byte_t *); - -/* frame interface */ - -struct id3_frame *id3_frame_new(char const *); -void id3_frame_delete(struct id3_frame *); - -union id3_field *id3_frame_field(struct id3_frame const *, unsigned int); - -/* field interface */ - -enum id3_field_type id3_field_type(union id3_field const *); - -int id3_field_setint(union id3_field *, signed long); -int id3_field_settextencoding(union id3_field *, enum id3_field_textencoding); -int id3_field_setstrings(union id3_field *, unsigned int, id3_ucs4_t **); -int id3_field_addstring(union id3_field *, id3_ucs4_t const *); -int id3_field_setlanguage(union id3_field *, char const *); -int id3_field_setlatin1(union id3_field *, id3_latin1_t const *); -int id3_field_setfulllatin1(union id3_field *, id3_latin1_t const *); -int id3_field_setstring(union id3_field *, id3_ucs4_t const *); -int id3_field_setfullstring(union id3_field *, id3_ucs4_t const *); -int id3_field_setframeid(union id3_field *, char const *); -int id3_field_setbinarydata(union id3_field *, - id3_byte_t const *, id3_length_t); - -signed long id3_field_getint(union id3_field const *); -enum id3_field_textencoding id3_field_gettextencoding(union id3_field const *); -id3_latin1_t const *id3_field_getlatin1(union id3_field const *); -id3_latin1_t const *id3_field_getfulllatin1(union id3_field const *); -id3_ucs4_t const *id3_field_getstring(union id3_field const *); -id3_ucs4_t const *id3_field_getfullstring(union id3_field const *); -unsigned int id3_field_getnstrings(union id3_field const *); -id3_ucs4_t const *id3_field_getstrings(union id3_field const *, - unsigned int); -char const *id3_field_getframeid(union id3_field const *); -id3_byte_t const *id3_field_getbinarydata(union id3_field const *, - id3_length_t *); - -/* genre interface */ - -id3_ucs4_t const *id3_genre_index(unsigned int); -id3_ucs4_t const *id3_genre_name(id3_ucs4_t const *); -int id3_genre_number(id3_ucs4_t const *); - -/* ucs4 interface */ - -id3_latin1_t *id3_ucs4_latin1duplicate(id3_ucs4_t const *); -id3_utf16_t *id3_ucs4_utf16duplicate(id3_ucs4_t const *); -id3_utf8_t *id3_ucs4_utf8duplicate(id3_ucs4_t const *); - -void id3_ucs4_putnumber(id3_ucs4_t *, unsigned long); -unsigned long id3_ucs4_getnumber(id3_ucs4_t const *); - -/* latin1/utf16/utf8 interfaces */ - -id3_ucs4_t *id3_latin1_ucs4duplicate(id3_latin1_t const *); -id3_ucs4_t *id3_utf16_ucs4duplicate(id3_utf16_t const *); -id3_ucs4_t *id3_utf8_ucs4duplicate(id3_utf8_t const *); - -/* version interface */ - -# define ID3_VERSION_MAJOR 0 -# define ID3_VERSION_MINOR 15 -# define ID3_VERSION_PATCH 1 -# define ID3_VERSION_EXTRA " (beta)" - -# define ID3_VERSION_STRINGIZE(str) #str -# define ID3_VERSION_STRING(num) ID3_VERSION_STRINGIZE(num) - -# define ID3_VERSION ID3_VERSION_STRING(ID3_VERSION_MAJOR) "." \ - ID3_VERSION_STRING(ID3_VERSION_MINOR) "." \ - ID3_VERSION_STRING(ID3_VERSION_PATCH) \ - ID3_VERSION_EXTRA - -# define ID3_PUBLISHYEAR "2000-2004" -# define ID3_AUTHOR "Underbit Technologies, Inc." -# define ID3_EMAIL "info@underbit.com" - -extern char const id3_version[]; -extern char const id3_copyright[]; -extern char const id3_author[]; -extern char const id3_build[]; - -# ifdef __cplusplus -} -# endif - -# endif diff --git a/src/libid3tag/latin1.c b/src/libid3tag/latin1.c deleted file mode 100644 index 67b8199..0000000 --- a/src/libid3tag/latin1.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: latin1.c,v 1.10 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <stdlib.h> - -# include "id3tag.h" -# include "latin1.h" -# include "ucs4.h" - -/* - * NAME: latin1->length() - * DESCRIPTION: return the number of ucs4 chars represented by a latin1 string - */ -id3_length_t id3_latin1_length(id3_latin1_t const *latin1) -{ - id3_latin1_t const *ptr = latin1; - - while (*ptr) - ++ptr; - - return ptr - latin1; -} - -/* - * NAME: latin1->size() - * DESCRIPTION: return the encoding size of a latin1 string - */ -id3_length_t id3_latin1_size(id3_latin1_t const *latin1) -{ - return id3_latin1_length(latin1) + 1; -} - -/* - * NAME: latin1->copy() - * DESCRIPTION: copy a latin1 string - */ -void id3_latin1_copy(id3_latin1_t *dest, id3_latin1_t const *src) -{ - while ((*dest++ = *src++)) - ; -} - -/* - * NAME: latin1->duplicate() - * DESCRIPTION: duplicate a latin1 string - */ -id3_latin1_t *id3_latin1_duplicate(id3_latin1_t const *src) -{ - id3_latin1_t *latin1; - - latin1 = malloc(id3_latin1_size(src) * sizeof(*latin1)); - if (latin1) - id3_latin1_copy(latin1, src); - - return latin1; -} - -/* - * NAME: latin1->ucs4duplicate() - * DESCRIPTION: duplicate and decode a latin1 string into ucs4 - */ -id3_ucs4_t *id3_latin1_ucs4duplicate(id3_latin1_t const *latin1) -{ - id3_ucs4_t *ucs4; - - ucs4 = malloc((id3_latin1_length(latin1) + 1) * sizeof(*ucs4)); - if (ucs4) - id3_latin1_decode(latin1, ucs4); - - return release(ucs4); -} - -/* - * NAME: latin1->decodechar() - * DESCRIPTION: decode a (single) latin1 char into a single ucs4 char - */ -id3_length_t id3_latin1_decodechar(id3_latin1_t const *latin1, - id3_ucs4_t *ucs4) -{ - *ucs4 = *latin1; - - return 1; -} - -/* - * NAME: latin1->encodechar() - * DESCRIPTION: encode a single ucs4 char into a (single) latin1 char - */ -id3_length_t id3_latin1_encodechar(id3_latin1_t *latin1, id3_ucs4_t ucs4) -{ - *latin1 = ucs4; - if (ucs4 > 0x000000ffL) - *latin1 = ID3_UCS4_REPLACEMENTCHAR; - - return 1; -} - -/* - * NAME: latin1->decode() - * DESCRIPTION: decode a complete latin1 string into a ucs4 string - */ -void id3_latin1_decode(id3_latin1_t const *latin1, id3_ucs4_t *ucs4) -{ - do - latin1 += id3_latin1_decodechar(latin1, ucs4); - while (*ucs4++); -} - -/* - * NAME: latin1->encode() - * DESCRIPTION: encode a complete ucs4 string into a latin1 string - */ -void id3_latin1_encode(id3_latin1_t *latin1, id3_ucs4_t const *ucs4) -{ - do - latin1 += id3_latin1_encodechar(latin1, *ucs4); - while (*ucs4++); -} - -/* - * NAME: latin1->put() - * DESCRIPTION: serialize a single latin1 character - */ -id3_length_t id3_latin1_put(id3_byte_t **ptr, id3_latin1_t latin1) -{ - if (ptr) - *(*ptr)++ = latin1; - - return 1; -} - -/* - * NAME: latin1->get() - * DESCRIPTION: deserialize a single latin1 character - */ -id3_latin1_t id3_latin1_get(id3_byte_t const **ptr) -{ - return *(*ptr)++; -} - -/* - * NAME: latin1->serialize() - * DESCRIPTION: serialize a ucs4 string using latin1 encoding - */ -id3_length_t id3_latin1_serialize(id3_byte_t **ptr, id3_ucs4_t const *ucs4, - int terminate) -{ - id3_length_t size = 0; - id3_latin1_t latin1[1], *out; - - while (*ucs4) { - switch (id3_latin1_encodechar(out = latin1, *ucs4++)) { - case 1: size += id3_latin1_put(ptr, *out++); - case 0: break; - } - } - - if (terminate) - size += id3_latin1_put(ptr, 0); - - return size; -} - -/* - * NAME: latin1->deserialize() - * DESCRIPTION: deserialize a ucs4 string using latin1 encoding - */ -id3_ucs4_t *id3_latin1_deserialize(id3_byte_t const **ptr, id3_length_t length) -{ - id3_byte_t const *end; - id3_latin1_t *latin1ptr, *latin1; - id3_ucs4_t *ucs4; - - end = *ptr + length; - - latin1 = malloc((length + 1) * sizeof(*latin1)); - if (latin1 == 0) - return 0; - - latin1ptr = latin1; - while (end - *ptr > 0 && (*latin1ptr = id3_latin1_get(ptr))) - ++latin1ptr; - - *latin1ptr = 0; - - ucs4 = malloc((id3_latin1_length(latin1) + 1) * sizeof(*ucs4)); - if (ucs4) - id3_latin1_decode(latin1, ucs4); - - free(latin1); - - return ucs4; -} diff --git a/src/libid3tag/latin1.h b/src/libid3tag/latin1.h deleted file mode 100644 index 3604bbf..0000000 --- a/src/libid3tag/latin1.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: latin1.h,v 1.8 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_LATIN1_H -# define LIBID3TAG_LATIN1_H - -# include "id3tag.h" - -id3_length_t id3_latin1_length(id3_latin1_t const *); -id3_length_t id3_latin1_size(id3_latin1_t const *); - -void id3_latin1_copy(id3_latin1_t *, id3_latin1_t const *); -id3_latin1_t *id3_latin1_duplicate(id3_latin1_t const *); - -id3_length_t id3_latin1_decodechar(id3_latin1_t const *, id3_ucs4_t *); -id3_length_t id3_latin1_encodechar(id3_latin1_t *, id3_ucs4_t); - -void id3_latin1_decode(id3_latin1_t const *, id3_ucs4_t *); -void id3_latin1_encode(id3_latin1_t *, id3_ucs4_t const *); - -id3_length_t id3_latin1_put(id3_byte_t **, id3_latin1_t); -id3_latin1_t id3_latin1_get(id3_byte_t const **); - -id3_length_t id3_latin1_serialize(id3_byte_t **, id3_ucs4_t const *, int); -id3_ucs4_t *id3_latin1_deserialize(id3_byte_t const **, id3_length_t); - -# endif diff --git a/src/libid3tag/parse.c b/src/libid3tag/parse.c deleted file mode 100644 index 86a3f21..0000000 --- a/src/libid3tag/parse.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: parse.c,v 1.9 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# ifdef HAVE_ASSERT_H -# include <assert.h> -# endif - -# include <stdlib.h> -# include <string.h> - -# include "id3tag.h" -# include "parse.h" -# include "latin1.h" -# include "utf16.h" -# include "utf8.h" - -signed long id3_parse_int(id3_byte_t const **ptr, unsigned int bytes) -{ - signed long value = 0; - - assert(bytes >= 1 && bytes <= 4); - - if (**ptr & 0x80) - value = ~0; - - switch (bytes) { - case 4: value = (value << 8) | *(*ptr)++; - case 3: value = (value << 8) | *(*ptr)++; - case 2: value = (value << 8) | *(*ptr)++; - case 1: value = (value << 8) | *(*ptr)++; - } - - return value; -} - -unsigned long id3_parse_uint(id3_byte_t const **ptr, unsigned int bytes) -{ - unsigned long value = 0; - - assert(bytes >= 1 && bytes <= 4); - - switch (bytes) { - case 4: value = (value << 8) | *(*ptr)++; - case 3: value = (value << 8) | *(*ptr)++; - case 2: value = (value << 8) | *(*ptr)++; - case 1: value = (value << 8) | *(*ptr)++; - } - - return value; -} - -unsigned long id3_parse_syncsafe(id3_byte_t const **ptr, unsigned int bytes) -{ - unsigned long value = 0; - - assert(bytes == 4 || bytes == 5); - - switch (bytes) { - case 5: value = (value << 4) | (*(*ptr)++ & 0x0f); - case 4: value = (value << 7) | (*(*ptr)++ & 0x7f); - value = (value << 7) | (*(*ptr)++ & 0x7f); - value = (value << 7) | (*(*ptr)++ & 0x7f); - value = (value << 7) | (*(*ptr)++ & 0x7f); - } - - return value; -} - -void id3_parse_immediate(id3_byte_t const **ptr, unsigned int bytes, - char *value) -{ - assert(value); - assert(bytes == 8 || bytes == 4 || bytes == 3); - - switch (bytes) { - case 8: *value++ = *(*ptr)++; - *value++ = *(*ptr)++; - *value++ = *(*ptr)++; - *value++ = *(*ptr)++; - case 4: *value++ = *(*ptr)++; - case 3: *value++ = *(*ptr)++; - *value++ = *(*ptr)++; - *value++ = *(*ptr)++; - } - - *value = 0; -} - -id3_latin1_t *id3_parse_latin1(id3_byte_t const **ptr, id3_length_t length, - int full) -{ - id3_byte_t const *end; - int terminated = 0; - id3_latin1_t *latin1; - - end = memchr(*ptr, 0, length); - if (end == 0) - end = *ptr + length; - else { - length = end - *ptr; - terminated = 1; - } - - latin1 = malloc(length + 1); - if (latin1) { - memcpy(latin1, *ptr, length); - latin1[length] = 0; - - if (!full) { - id3_latin1_t *check; - - for (check = latin1; *check; ++check) { - if (*check == '\n') - *check = ' '; - } - } - } - - *ptr += length + terminated; - - return latin1; -} - -id3_ucs4_t *id3_parse_string(id3_byte_t const **ptr, id3_length_t length, - enum id3_field_textencoding encoding, int full) -{ - id3_ucs4_t *ucs4 = 0; - enum id3_utf16_byteorder byteorder = ID3_UTF16_BYTEORDER_ANY; - - switch (encoding) { - case ID3_FIELD_TEXTENCODING_ISO_8859_1: - ucs4 = id3_latin1_deserialize(ptr, length); - break; - - case ID3_FIELD_TEXTENCODING_UTF_16BE: - byteorder = ID3_UTF16_BYTEORDER_BE; - case ID3_FIELD_TEXTENCODING_UTF_16: - ucs4 = id3_utf16_deserialize(ptr, length, byteorder); - break; - - case ID3_FIELD_TEXTENCODING_UTF_8: - ucs4 = id3_utf8_deserialize(ptr, length); - break; - } - - if (ucs4 && !full) { - id3_ucs4_t *check; - - for (check = ucs4; *check; ++check) { - if (*check == '\n') - *check = ' '; - } - } - - return ucs4; -} - -id3_byte_t *id3_parse_binary(id3_byte_t const **ptr, id3_length_t length) -{ - id3_byte_t *data; - - if (length == 0) - return malloc(1); - - data = malloc(length); - if (data) - memcpy(data, *ptr, length); - - *ptr += length; - - return data; -} diff --git a/src/libid3tag/parse.h b/src/libid3tag/parse.h deleted file mode 100644 index 5dfa23f..0000000 --- a/src/libid3tag/parse.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: parse.h,v 1.6 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_PARSE_H -# define LIBID3TAG_PARSE_H - -signed long id3_parse_int(id3_byte_t const **, unsigned int); -unsigned long id3_parse_uint(id3_byte_t const **, unsigned int); -unsigned long id3_parse_syncsafe(id3_byte_t const **, unsigned int); -void id3_parse_immediate(id3_byte_t const **, unsigned int, char *); -id3_latin1_t *id3_parse_latin1(id3_byte_t const **, id3_length_t, int); -id3_ucs4_t *id3_parse_string(id3_byte_t const **, id3_length_t, - enum id3_field_textencoding, int); -id3_byte_t *id3_parse_binary(id3_byte_t const **, id3_length_t); - -# endif diff --git a/src/libid3tag/render.c b/src/libid3tag/render.c deleted file mode 100644 index b699945..0000000 --- a/src/libid3tag/render.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: render.c,v 1.11 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <string.h> -# include <stdlib.h> - -# ifdef HAVE_ASSERT_H -# include <assert.h> -# endif - -# include "id3tag.h" -# include "render.h" -# include "ucs4.h" -# include "latin1.h" -# include "utf16.h" -# include "utf8.h" - -id3_length_t id3_render_immediate(id3_byte_t **ptr, - char const *value, unsigned int bytes) -{ - assert(value); - assert(bytes == 8 || bytes == 4 || bytes == 3); - - if (ptr) { - switch (bytes) { - case 8: *(*ptr)++ = *value++; - *(*ptr)++ = *value++; - *(*ptr)++ = *value++; - *(*ptr)++ = *value++; - case 4: *(*ptr)++ = *value++; - case 3: *(*ptr)++ = *value++; - *(*ptr)++ = *value++; - *(*ptr)++ = *value++; - } - } - - return bytes; -} - -id3_length_t id3_render_syncsafe(id3_byte_t **ptr, - unsigned long num, unsigned int bytes) -{ - assert(bytes == 4 || bytes == 5); - - if (ptr) { - switch (bytes) { - case 5: *(*ptr)++ = (num >> 28) & 0x0f; - case 4: *(*ptr)++ = (num >> 21) & 0x7f; - *(*ptr)++ = (num >> 14) & 0x7f; - *(*ptr)++ = (num >> 7) & 0x7f; - *(*ptr)++ = (num >> 0) & 0x7f; - } - } - - return bytes; -} - -id3_length_t id3_render_int(id3_byte_t **ptr, - signed long num, unsigned int bytes) -{ - assert(bytes >= 1 && bytes <= 4); - - if (ptr) { - switch (bytes) { - case 4: *(*ptr)++ = num >> 24; - case 3: *(*ptr)++ = num >> 16; - case 2: *(*ptr)++ = num >> 8; - case 1: *(*ptr)++ = num >> 0; - } - } - - return bytes; -} - -id3_length_t id3_render_binary(id3_byte_t **ptr, - id3_byte_t const *data, id3_length_t length) -{ - if (data == 0) - return 0; - - if (ptr) { - memcpy(*ptr, data, length); - *ptr += length; - } - - return length; -} - -id3_length_t id3_render_latin1(id3_byte_t **ptr, - id3_latin1_t const *latin1, int terminate) -{ - id3_length_t size; - - if (latin1 == 0) - latin1 = (id3_latin1_t *)""; - - size = id3_latin1_size(latin1); - if (!terminate) - --size; - - if (ptr) { - memcpy(*ptr, latin1, size); - *ptr += size; - } - - return size; -} - -id3_length_t id3_render_string(id3_byte_t **ptr, id3_ucs4_t const *ucs4, - enum id3_field_textencoding encoding, - int terminate) -{ - enum id3_utf16_byteorder byteorder = ID3_UTF16_BYTEORDER_ANY; - - if (ucs4 == 0) - ucs4 = id3_ucs4_empty; - - switch (encoding) { - case ID3_FIELD_TEXTENCODING_ISO_8859_1: - return id3_latin1_serialize(ptr, ucs4, terminate); - - case ID3_FIELD_TEXTENCODING_UTF_16BE: - byteorder = ID3_UTF16_BYTEORDER_BE; - case ID3_FIELD_TEXTENCODING_UTF_16: - return id3_utf16_serialize(ptr, ucs4, byteorder, terminate); - - case ID3_FIELD_TEXTENCODING_UTF_8: - return id3_utf8_serialize(ptr, ucs4, terminate); - } - - return 0; -} - -id3_length_t id3_render_padding(id3_byte_t **ptr, id3_byte_t value, - id3_length_t length) -{ - if (ptr) { - memset(*ptr, value, length); - *ptr += length; - } - - return length; -} - -/* - * NAME: render->paddedstring() - * DESCRIPTION: render a space-padded string using latin1 encoding - */ -id3_length_t id3_render_paddedstring(id3_byte_t **ptr, id3_ucs4_t const *ucs4, - id3_length_t length) -{ - id3_ucs4_t padded[31], *data, *end; - - /* latin1 encoding only (this is used for ID3v1 fields) */ - - assert(length <= 30); - - data = padded; - end = data + length; - - if (ucs4) { - while (*ucs4 && end - data > 0) { - *data++ = *ucs4++; - - if (data[-1] == '\n') - data[-1] = ' '; - } - } - - while (end - data > 0) - *data++ = ' '; - - *data = 0; - - return id3_latin1_serialize(ptr, padded, 0); -} diff --git a/src/libid3tag/render.h b/src/libid3tag/render.h deleted file mode 100644 index 702605d..0000000 --- a/src/libid3tag/render.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: render.h,v 1.7 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_RENDER_H -# define LIBID3TAG_RENDER_H - -# include "id3tag.h" - -id3_length_t id3_render_immediate(id3_byte_t **, char const *, unsigned int); -id3_length_t id3_render_syncsafe(id3_byte_t **, unsigned long, unsigned int); -id3_length_t id3_render_int(id3_byte_t **, signed long, unsigned int); -id3_length_t id3_render_binary(id3_byte_t **, - id3_byte_t const *, id3_length_t); -id3_length_t id3_render_latin1(id3_byte_t **, id3_latin1_t const *, int); -id3_length_t id3_render_string(id3_byte_t **, id3_ucs4_t const *, - enum id3_field_textencoding, int); -id3_length_t id3_render_padding(id3_byte_t **, id3_byte_t, id3_length_t); - -id3_length_t id3_render_paddedstring(id3_byte_t **, id3_ucs4_t const *, - id3_length_t); - -# endif diff --git a/src/libid3tag/tag.c b/src/libid3tag/tag.c deleted file mode 100644 index 0323355..0000000 --- a/src/libid3tag/tag.c +++ /dev/null @@ -1,912 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: tag.c,v 1.20 2004/02/17 02:04:10 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <string.h> -# include <stdlib.h> - -# ifdef HAVE_ASSERT_H -# include <assert.h> -# endif - -# include "id3tag.h" -# include "tag.h" -# include "frame.h" -# include "compat.h" -# include "parse.h" -# include "render.h" -# include "latin1.h" -# include "ucs4.h" -# include "genre.h" -# include "crc.h" -# include "field.h" -# include "util.h" - -/* - * NAME: tag->new() - * DESCRIPTION: allocate and return a new, empty tag - */ -struct id3_tag *id3_tag_new(void) -{ - struct id3_tag *tag; - - tag = malloc(sizeof(*tag)); - if (tag) { - tag->refcount = 0; - tag->version = ID3_TAG_VERSION; - tag->flags = 0; - tag->extendedflags = 0; - tag->restrictions = 0; - tag->options = /* ID3_TAG_OPTION_UNSYNCHRONISATION | */ - ID3_TAG_OPTION_COMPRESSION | ID3_TAG_OPTION_CRC; - tag->nframes = 0; - tag->frames = 0; - tag->paddedsize = 0; - } - - return tag; -} - -/* - * NAME: tag->delete() - * DESCRIPTION: destroy a tag and deallocate all associated memory - */ -void id3_tag_delete(struct id3_tag *tag) -{ - assert(tag); - - if (tag->refcount == 0) { - id3_tag_clearframes(tag); - - if (tag->frames) - free(tag->frames); - - free(tag); - } -} - -/* - * NAME: tag->addref() - * DESCRIPTION: add an external reference to a tag - */ -void id3_tag_addref(struct id3_tag *tag) -{ - assert(tag); - - ++tag->refcount; -} - -/* - * NAME: tag->delref() - * DESCRIPTION: remove an external reference to a tag - */ -void id3_tag_delref(struct id3_tag *tag) -{ - assert(tag && tag->refcount > 0); - - --tag->refcount; -} - -/* - * NAME: tag->version() - * DESCRIPTION: return the tag's original ID3 version number - */ -unsigned int id3_tag_version(struct id3_tag const *tag) -{ - assert(tag); - - return tag->version; -} - -/* - * NAME: tag->options() - * DESCRIPTION: get or set tag options - */ -int id3_tag_options(struct id3_tag *tag, int mask, int values) -{ - assert(tag); - - if (mask) - tag->options = (tag->options & ~mask) | (values & mask); - - return tag->options; -} - -/* - * NAME: tag->setlength() - * DESCRIPTION: set the minimum rendered tag size - */ -void id3_tag_setlength(struct id3_tag *tag, id3_length_t length) -{ - assert(tag); - - tag->paddedsize = length; -} - -/* - * NAME: tag->clearframes() - * DESCRIPTION: detach and delete all frames associated with a tag - */ -void id3_tag_clearframes(struct id3_tag *tag) -{ - unsigned int i; - - assert(tag); - - for (i = 0; i < tag->nframes; ++i) { - id3_frame_delref(tag->frames[i]); - id3_frame_delete(tag->frames[i]); - } - - tag->nframes = 0; -} - -/* - * NAME: tag->attachframe() - * DESCRIPTION: attach a frame to a tag - */ -int id3_tag_attachframe(struct id3_tag *tag, struct id3_frame *frame) -{ - struct id3_frame **frames; - - assert(tag && frame); - - frames = realloc(tag->frames, (tag->nframes + 1) * sizeof(*frames)); - if (frames == 0) - return -1; - - tag->frames = frames; - tag->frames[tag->nframes++] = frame; - - id3_frame_addref(frame); - - return 0; -} - -/* - * NAME: tag->detachframe() - * DESCRIPTION: detach (but don't delete) a frame from a tag - */ -int id3_tag_detachframe(struct id3_tag *tag, struct id3_frame *frame) -{ - unsigned int i; - - assert(tag && frame); - - for (i = 0; i < tag->nframes; ++i) { - if (tag->frames[i] == frame) - break; - } - - if (i == tag->nframes) - return -1; - - --tag->nframes; - while (i++ < tag->nframes) - tag->frames[i - 1] = tag->frames[i]; - - id3_frame_delref(frame); - - return 0; -} - -/* - * NAME: tag->findframe() - * DESCRIPTION: find in a tag the nth (0-based) frame with the given frame ID - */ -struct id3_frame *id3_tag_findframe(struct id3_tag const *tag, - char const *id, unsigned int index) -{ - unsigned int len, i; - - assert(tag); - - if (id == 0 || *id == 0) - return (index < tag->nframes) ? tag->frames[index] : 0; - - len = strlen(id); - - if (len == 4) { - struct id3_compat const *compat; - - compat = id3_compat_lookup(id, len); - if (compat && compat->equiv && !compat->translate) { - id = compat->equiv; - len = strlen(id); - } - } - - for (i = 0; i < tag->nframes; ++i) { - if (strncmp(tag->frames[i]->id, id, len) == 0 && index-- == 0) - return tag->frames[i]; - } - - return 0; -} - -enum tagtype { - TAGTYPE_NONE = 0, - TAGTYPE_ID3V1, - TAGTYPE_ID3V2, - TAGTYPE_ID3V2_FOOTER -}; - -static -enum tagtype tagtype(id3_byte_t const *data, id3_length_t length) -{ - if (length >= 3 && - data[0] == 'T' && data[1] == 'A' && data[2] == 'G') - return TAGTYPE_ID3V1; - - if (length >= 10 && - ((data[0] == 'I' && data[1] == 'D' && data[2] == '3') || - (data[0] == '3' && data[1] == 'D' && data[2] == 'I')) && - data[3] < 0xff && data[4] < 0xff && - data[6] < 0x80 && data[7] < 0x80 && data[8] < 0x80 && data[9] < 0x80) - return data[0] == 'I' ? TAGTYPE_ID3V2 : TAGTYPE_ID3V2_FOOTER; - - return TAGTYPE_NONE; -} - -static -void parse_header(id3_byte_t const **ptr, - unsigned int *version, int *flags, id3_length_t *size) -{ - *ptr += 3; - - *version = id3_parse_uint(ptr, 2); - *flags = id3_parse_uint(ptr, 1); - *size = id3_parse_syncsafe(ptr, 4); -} - -/* - * NAME: tag->query() - * DESCRIPTION: if a tag begins at the given location, return its size - */ -signed long id3_tag_query(id3_byte_t const *data, id3_length_t length) -{ - unsigned int version; - int flags; - id3_length_t size; - - assert(data); - - switch (tagtype(data, length)) { - case TAGTYPE_ID3V1: - return 128; - - case TAGTYPE_ID3V2: - parse_header(&data, &version, &flags, &size); - - if (flags & ID3_TAG_FLAG_FOOTERPRESENT) - size += 10; - - return 10 + size; - - case TAGTYPE_ID3V2_FOOTER: - parse_header(&data, &version, &flags, &size); - return -size - 10; - - case TAGTYPE_NONE: - break; - } - - return 0; -} - -static -void trim(char *str) -{ - char *ptr; - - ptr = str + strlen(str); - while (ptr > str && ptr[-1] == ' ') - --ptr; - - *ptr = 0; -} - -static -int v1_attachstr(struct id3_tag *tag, char const *id, - id3_byte_t *text, unsigned long number) -{ - struct id3_frame *frame; - id3_ucs4_t ucs4[31]; - - if (text) { - trim((char *)text); - if (*text == 0) - return 0; - } - - frame = id3_frame_new(id); - if (frame == 0) - return -1; - - if (id3_field_settextencoding(&frame->fields[0], - ID3_FIELD_TEXTENCODING_ISO_8859_1) == -1) - goto fail; - - if (text) - id3_latin1_decode((id3_latin1_t *)text, ucs4); - else - id3_ucs4_putnumber(ucs4, number); - - if (strcmp(id, ID3_FRAME_COMMENT) == 0) { - if (id3_field_setlanguage(&frame->fields[1], "XXX") == -1 || - id3_field_setstring(&frame->fields[2], id3_ucs4_empty) == -1 || - id3_field_setfullstring(&frame->fields[3], ucs4) == -1) - goto fail; - } - else { - id3_ucs4_t *ptr = ucs4; - - if (id3_field_setstrings(&frame->fields[1], 1, &ptr) == -1) - goto fail; - } - - if (id3_tag_attachframe(tag, frame) == -1) - goto fail; - - return 0; - - fail: - id3_frame_delete(frame); - return -1; -} - -static -struct id3_tag *v1_parse(id3_byte_t const *data) -{ - struct id3_tag *tag; - - tag = id3_tag_new(); - if (tag) { - id3_byte_t title[31], artist[31], album[31], year[5], comment[31]; - unsigned int genre, track; - - tag->version = 0x0100; - - tag->options |= ID3_TAG_OPTION_ID3V1; - tag->options &= ~ID3_TAG_OPTION_COMPRESSION; - - tag->restrictions = - ID3_TAG_RESTRICTION_TEXTENCODING_LATIN1_UTF8 | - ID3_TAG_RESTRICTION_TEXTSIZE_30_CHARS; - - title[30] = artist[30] = album[30] = year[4] = comment[30] = 0; - - memcpy(title, &data[3], 30); - memcpy(artist, &data[33], 30); - memcpy(album, &data[63], 30); - memcpy(year, &data[93], 4); - memcpy(comment, &data[97], 30); - - genre = data[127]; - - track = 0; - if (comment[28] == 0 && comment[29] != 0) { - track = comment[29]; - tag->version = 0x0101; - } - - /* populate tag frames */ - - if (v1_attachstr(tag, ID3_FRAME_TITLE, title, 0) == -1 || - v1_attachstr(tag, ID3_FRAME_ARTIST, artist, 0) == -1 || - v1_attachstr(tag, ID3_FRAME_ALBUM, album, 0) == -1 || - v1_attachstr(tag, ID3_FRAME_YEAR, year, 0) == -1 || - (track && v1_attachstr(tag, ID3_FRAME_TRACK, 0, track) == -1) || - (genre < 0xff && v1_attachstr(tag, ID3_FRAME_GENRE, 0, genre) == -1) || - v1_attachstr(tag, ID3_FRAME_COMMENT, comment, 0) == -1) { - id3_tag_delete(tag); - tag = 0; - } - } - - return tag; -} - -static -struct id3_tag *v2_parse(id3_byte_t const *ptr) -{ - struct id3_tag *tag; - id3_byte_t *mem = 0; - - tag = id3_tag_new(); - if (tag) { - id3_byte_t const *end; - id3_length_t size; - - parse_header(&ptr, &tag->version, &tag->flags, &size); - - tag->paddedsize = 10 + size; - - if ((tag->flags & ID3_TAG_FLAG_UNSYNCHRONISATION) && - ID3_TAG_VERSION_MAJOR(tag->version) < 4) { - mem = malloc(size); - if (mem == 0) - goto fail; - - memcpy(mem, ptr, size); - - size = id3_util_deunsynchronise(mem, size); - ptr = mem; - } - - end = ptr + size; - - if (tag->flags & ID3_TAG_FLAG_EXTENDEDHEADER) { - switch (ID3_TAG_VERSION_MAJOR(tag->version)) { - case 2: - goto fail; - - case 3: - { - id3_byte_t const *ehptr, *ehend; - id3_length_t ehsize; - - enum { - EH_FLAG_CRC = 0x8000 /* CRC data present */ - }; - - if (end - ptr < 4) - goto fail; - - ehsize = id3_parse_uint(&ptr, 4); - - if (ehsize > end - ptr) - goto fail; - - ehptr = ptr; - ehend = ptr + ehsize; - - ptr = ehend; - - if (ehend - ehptr >= 6) { - int ehflags; - id3_length_t padsize; - - ehflags = id3_parse_uint(&ehptr, 2); - padsize = id3_parse_uint(&ehptr, 4); - - if (padsize > end - ptr) - goto fail; - - end -= padsize; - - if (ehflags & EH_FLAG_CRC) { - unsigned long crc; - - if (ehend - ehptr < 4) - goto fail; - - crc = id3_parse_uint(&ehptr, 4); - - if (crc != id3_crc_compute(ptr, end - ptr)) - goto fail; - - tag->extendedflags |= ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT; - } - } - } - break; - - case 4: - { - id3_byte_t const *ehptr, *ehend; - id3_length_t ehsize; - unsigned int bytes; - - if (end - ptr < 4) - goto fail; - - ehptr = ptr; - ehsize = id3_parse_syncsafe(&ptr, 4); - - if (ehsize < 6 || ehsize > end - ehptr) - goto fail; - - ehend = ehptr + ehsize; - - bytes = id3_parse_uint(&ptr, 1); - - if (bytes < 1 || bytes > ehend - ptr) - goto fail; - - ehptr = ptr + bytes; - - /* verify extended header size */ - { - id3_byte_t const *flagsptr = ptr, *dataptr = ehptr; - unsigned int datalen; - int ehflags; - - while (bytes--) { - for (ehflags = id3_parse_uint(&flagsptr, 1); ehflags; - ehflags = (ehflags << 1) & 0xff) { - if (ehflags & 0x80) { - if (dataptr == ehend) - goto fail; - datalen = id3_parse_uint(&dataptr, 1); - if (datalen > 0x7f || datalen > ehend - dataptr) - goto fail; - dataptr += datalen; - } - } - } - } - - tag->extendedflags = id3_parse_uint(&ptr, 1); - - ptr = ehend; - - if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE) { - bytes = id3_parse_uint(&ehptr, 1); - ehptr += bytes; - } - - if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT) { - unsigned long crc; - - bytes = id3_parse_uint(&ehptr, 1); - if (bytes < 5) - goto fail; - - crc = id3_parse_syncsafe(&ehptr, 5); - ehptr += bytes - 5; - - if (crc != id3_crc_compute(ptr, end - ptr)) - goto fail; - } - - if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS) { - bytes = id3_parse_uint(&ehptr, 1); - if (bytes < 1) - goto fail; - - tag->restrictions = id3_parse_uint(&ehptr, 1); - ehptr += bytes - 1; - } - } - break; - } - } - - /* frames */ - - while (ptr < end) { - struct id3_frame *frame; - - if (*ptr == 0) - break; /* padding */ - - frame = id3_frame_parse(&ptr, end - ptr, tag->version); - if (frame == 0 || id3_tag_attachframe(tag, frame) == -1) - goto fail; - } - - if (ID3_TAG_VERSION_MAJOR(tag->version) < 4 && - id3_compat_fixup(tag) == -1) - goto fail; - } - - if (0) { - fail: - id3_tag_delete(tag); - tag = 0; - } - - if (mem) - free(mem); - - return tag; -} - -/* - * NAME: tag->parse() - * DESCRIPTION: parse a complete ID3 tag - */ -struct id3_tag *id3_tag_parse(id3_byte_t const *data, id3_length_t length) -{ - id3_byte_t const *ptr; - unsigned int version; - int flags; - id3_length_t size; - - assert(data); - - switch (tagtype(data, length)) { - case TAGTYPE_ID3V1: - return (length < 128) ? 0 : v1_parse(data); - - case TAGTYPE_ID3V2: - break; - - case TAGTYPE_ID3V2_FOOTER: - case TAGTYPE_NONE: - return 0; - } - - /* ID3v2.x */ - - ptr = data; - parse_header(&ptr, &version, &flags, &size); - - switch (ID3_TAG_VERSION_MAJOR(version)) { - case 4: - if (flags & ID3_TAG_FLAG_FOOTERPRESENT) - size += 10; - case 2: - case 3: - return (length < 10 + size) ? 0 : v2_parse(data); - } - - return 0; -} - -static -void v1_renderstr(struct id3_tag const *tag, char const *frameid, - id3_byte_t **buffer, id3_length_t length) -{ - struct id3_frame *frame; - id3_ucs4_t const *string; - - frame = id3_tag_findframe(tag, frameid, 0); - if (frame == 0) - string = id3_ucs4_empty; - else { - if (strcmp(frameid, ID3_FRAME_COMMENT) == 0) - string = id3_field_getfullstring(&frame->fields[3]); - else - string = id3_field_getstrings(&frame->fields[1], 0); - } - - id3_render_paddedstring(buffer, string, length); -} - -/* - * NAME: v1->render() - * DESCRIPTION: render an ID3v1 (or ID3v1.1) tag - */ -static -id3_length_t v1_render(struct id3_tag const *tag, id3_byte_t *buffer) -{ - id3_byte_t data[128], *ptr; - struct id3_frame *frame; - unsigned int i; - int genre = -1; - - ptr = data; - - id3_render_immediate(&ptr, "TAG", 3); - - v1_renderstr(tag, ID3_FRAME_TITLE, &ptr, 30); - v1_renderstr(tag, ID3_FRAME_ARTIST, &ptr, 30); - v1_renderstr(tag, ID3_FRAME_ALBUM, &ptr, 30); - v1_renderstr(tag, ID3_FRAME_YEAR, &ptr, 4); - v1_renderstr(tag, ID3_FRAME_COMMENT, &ptr, 30); - - /* ID3v1.1 track number */ - - frame = id3_tag_findframe(tag, ID3_FRAME_TRACK, 0); - if (frame) { - id3_ucs4_t const *string; - unsigned int track = 0; - - string = id3_field_getstrings(&frame->fields[1], 0); - if (string) - track = id3_ucs4_getnumber(string); - if (track > 0 && track <= 0xff) { - ptr[-2] = 0; - ptr[-1] = track; - } - } - - /* ID3v1 genre number */ - - frame = id3_tag_findframe(tag, ID3_FRAME_GENRE, 0); - if (frame) { - unsigned int nstrings; - - nstrings = id3_field_getnstrings(&frame->fields[1]); - - for (i = 0; i < nstrings; ++i) { - genre = id3_genre_number(id3_field_getstrings(&frame->fields[1], i)); - if (genre != -1) - break; - } - - if (i == nstrings && nstrings > 0) - genre = ID3_GENRE_OTHER; - } - - id3_render_int(&ptr, genre, 1); - - /* make sure the tag is not empty */ - - if (genre == -1) { - for (i = 3; i < 127; ++i) { - if (data[i] != ' ') - break; - } - - if (i == 127) - return 0; - } - - if (buffer) - memcpy(buffer, data, 128); - - return 128; -} - -/* - * NAME: tag->render() - * DESCRIPTION: render a complete ID3 tag - */ -id3_length_t id3_tag_render(struct id3_tag const *tag, id3_byte_t *buffer) -{ - id3_length_t size = 0; - id3_byte_t **ptr, - *header_ptr = 0, *tagsize_ptr = 0, *crc_ptr = 0, *frames_ptr = 0; - int flags, extendedflags; - unsigned int i; - - assert(tag); - - if (tag->options & ID3_TAG_OPTION_ID3V1) - return v1_render(tag, buffer); - - /* a tag must contain at least one (renderable) frame */ - - for (i = 0; i < tag->nframes; ++i) { - if (id3_frame_render(tag->frames[i], 0, 0) > 0) - break; - } - - if (i == tag->nframes) - return 0; - - ptr = buffer ? &buffer : 0; - - /* get flags */ - - flags = tag->flags & ID3_TAG_FLAG_KNOWNFLAGS; - extendedflags = tag->extendedflags & ID3_TAG_EXTENDEDFLAG_KNOWNFLAGS; - - extendedflags &= ~ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT; - if (tag->options & ID3_TAG_OPTION_CRC) - extendedflags |= ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT; - - extendedflags &= ~ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS; - if (tag->restrictions) - extendedflags |= ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS; - - flags &= ~ID3_TAG_FLAG_UNSYNCHRONISATION; - if (tag->options & ID3_TAG_OPTION_UNSYNCHRONISATION) - flags |= ID3_TAG_FLAG_UNSYNCHRONISATION; - - flags &= ~ID3_TAG_FLAG_EXTENDEDHEADER; - if (extendedflags) - flags |= ID3_TAG_FLAG_EXTENDEDHEADER; - - flags &= ~ID3_TAG_FLAG_FOOTERPRESENT; - if (tag->options & ID3_TAG_OPTION_APPENDEDTAG) - flags |= ID3_TAG_FLAG_FOOTERPRESENT; - - /* header */ - - if (ptr) - header_ptr = *ptr; - - size += id3_render_immediate(ptr, "ID3", 3); - size += id3_render_int(ptr, ID3_TAG_VERSION, 2); - size += id3_render_int(ptr, flags, 1); - - if (ptr) - tagsize_ptr = *ptr; - - size += id3_render_syncsafe(ptr, 0, 4); - - /* extended header */ - - if (flags & ID3_TAG_FLAG_EXTENDEDHEADER) { - id3_length_t ehsize = 0; - id3_byte_t *ehsize_ptr = 0; - - if (ptr) - ehsize_ptr = *ptr; - - ehsize += id3_render_syncsafe(ptr, 0, 4); - ehsize += id3_render_int(ptr, 1, 1); - ehsize += id3_render_int(ptr, extendedflags, 1); - - if (extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE) - ehsize += id3_render_int(ptr, 0, 1); - - if (extendedflags & ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT) { - ehsize += id3_render_int(ptr, 5, 1); - - if (ptr) - crc_ptr = *ptr; - - ehsize += id3_render_syncsafe(ptr, 0, 5); - } - - if (extendedflags & ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS) { - ehsize += id3_render_int(ptr, 1, 1); - ehsize += id3_render_int(ptr, tag->restrictions, 1); - } - - if (ehsize_ptr) - id3_render_syncsafe(&ehsize_ptr, ehsize, 4); - - size += ehsize; - } - - /* frames */ - - if (ptr) - frames_ptr = *ptr; - - for (i = 0; i < tag->nframes; ++i) - size += id3_frame_render(tag->frames[i], ptr, tag->options); - - /* padding */ - - if (!(flags & ID3_TAG_FLAG_FOOTERPRESENT)) { - if (size < tag->paddedsize) - size += id3_render_padding(ptr, 0, tag->paddedsize - size); - else if (tag->options & ID3_TAG_OPTION_UNSYNCHRONISATION) { - if (ptr == 0) - size += 1; - else { - if ((*ptr)[-1] == 0xff) - size += id3_render_padding(ptr, 0, 1); - } - } - } - - /* patch tag size and CRC */ - - if (tagsize_ptr) - id3_render_syncsafe(&tagsize_ptr, size - 10, 4); - - if (crc_ptr) { - id3_render_syncsafe(&crc_ptr, - id3_crc_compute(frames_ptr, *ptr - frames_ptr), 5); - } - - /* footer */ - - if (flags & ID3_TAG_FLAG_FOOTERPRESENT) { - size += id3_render_immediate(ptr, "3DI", 3); - size += id3_render_binary(ptr, header_ptr + 3, 7); - } - - return size; -} diff --git a/src/libid3tag/tag.h b/src/libid3tag/tag.h deleted file mode 100644 index 2ce84d7..0000000 --- a/src/libid3tag/tag.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: tag.h,v 1.10 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_TAG_H -# define LIBID3TAG_TAG_H - -# include "id3tag.h" - -void id3_tag_addref(struct id3_tag *); -void id3_tag_delref(struct id3_tag *); - -# endif diff --git a/src/libid3tag/ucs4.c b/src/libid3tag/ucs4.c deleted file mode 100644 index 56a587d..0000000 --- a/src/libid3tag/ucs4.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: ucs4.c,v 1.13 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <stdlib.h> - -# include "id3tag.h" -# include "ucs4.h" -# include "latin1.h" -# include "utf16.h" -# include "utf8.h" - -id3_ucs4_t const id3_ucs4_empty[] = { 0 }; - -/* - * NAME: ucs4->length() - * DESCRIPTION: return the number of ucs4 chars represented by a ucs4 string - */ -id3_length_t id3_ucs4_length(id3_ucs4_t const *ucs4) -{ - id3_ucs4_t const *ptr = ucs4; - - while (*ptr) - ++ptr; - - return ptr - ucs4; -} - -/* - * NAME: ucs4->size() - * DESCRIPTION: return the encoding size of a ucs4 string - */ -id3_length_t id3_ucs4_size(id3_ucs4_t const *ucs4) -{ - return id3_ucs4_length(ucs4) + 1; -} - -/* - * NAME: ucs4->latin1size() - * DESCRIPTION: return the encoding size of a latin1-encoded ucs4 string - */ -id3_length_t id3_ucs4_latin1size(id3_ucs4_t const *ucs4) -{ - return id3_ucs4_size(ucs4); -} - -/* - * NAME: ucs4->utf16size() - * DESCRIPTION: return the encoding size of a utf16-encoded ucs4 string - */ -id3_length_t id3_ucs4_utf16size(id3_ucs4_t const *ucs4) -{ - id3_length_t size = 0; - - while (*ucs4) { - ++size; - if (*ucs4 >= 0x00010000L && - *ucs4 <= 0x0010ffffL) - ++size; - - ++ucs4; - } - - return size + 1; -} - -/* - * NAME: ucs4->utf8size() - * DESCRIPTION: return the encoding size of a utf8-encoded ucs4 string - */ -id3_length_t id3_ucs4_utf8size(id3_ucs4_t const *ucs4) -{ - id3_length_t size = 0; - - while (*ucs4) { - if (*ucs4 <= 0x0000007fL) - size += 1; - else if (*ucs4 <= 0x000007ffL) - size += 2; - else if (*ucs4 <= 0x0000ffffL) - size += 3; - else if (*ucs4 <= 0x001fffffL) - size += 4; - else if (*ucs4 <= 0x03ffffffL) - size += 5; - else if (*ucs4 <= 0x7fffffffL) - size += 6; - else - size += 2; /* based on U+00B7 replacement char */ - - ++ucs4; - } - - return size + 1; -} - -/* - * NAME: ucs4->utf8size() - * DESCRIPTION: return the encoding size of a utf8-encoded ucs4 string - */ -id3_length_t id3_ucs4_multibytesize(id3_ucs4_t const *ucs4) -{ - id3_length_t size = 0; - - while (*ucs4) { - if (*ucs4 <= 0x0000007fL) - size += 1; - else if (*ucs4 <= 0x000007ffL) - size += 2; - else if (*ucs4 <= 0x0000ffffL) - size += 3; - else if (*ucs4 <= 0x001fffffL) - size += 4; - else if (*ucs4 <= 0x03ffffffL) - size += 5; - else if (*ucs4 <= 0x7fffffffL) - size += 6; - else - size += 2; /* based on U+00B7 replacement char */ - - ++ucs4; - } - - return size + 1; -} - -/* - * NAME: ucs4->latin1duplicate() - * DESCRIPTION: duplicate and encode a ucs4 string into latin1 - */ -id3_latin1_t *id3_ucs4_latin1duplicate(id3_ucs4_t const *ucs4) -{ - id3_latin1_t *latin1; - - latin1 = malloc(id3_ucs4_latin1size(ucs4) * sizeof(*latin1)); - if (latin1) - id3_latin1_encode(latin1, ucs4); - - return release(latin1); -} - -/* - * NAME: ucs4->utf16duplicate() - * DESCRIPTION: duplicate and encode a ucs4 string into utf16 - */ -id3_utf16_t *id3_ucs4_utf16duplicate(id3_ucs4_t const *ucs4) -{ - id3_utf16_t *utf16; - - utf16 = malloc(id3_ucs4_utf16size(ucs4) * sizeof(*utf16)); - if (utf16) - id3_utf16_encode(utf16, ucs4); - - return release(utf16); -} - -/* - * NAME: ucs4->utf8duplicate() - * DESCRIPTION: duplicate and encode a ucs4 string into utf8 - */ -id3_utf8_t *id3_ucs4_utf8duplicate(id3_ucs4_t const *ucs4) -{ - id3_utf8_t *utf8; - - utf8 = malloc(id3_ucs4_utf8size(ucs4) * sizeof(*utf8)); - if (utf8) - id3_utf8_encode(utf8, ucs4); - - return release(utf8); -} - -#if 0 -void id3_multibyte_encode(id3_latin1_t *multi, id3_ucs4_t const *ucs4) -{ - id3_latin1_t *mptr; - id3_ucs4_t *uptr; - int multi - //prescan - - // 1. if threre is multi byte entry, the string must be multi byte unicode string. - // -> convert into utf-8 - // 2. if thre is no multi byte entry and there is a single byte character - - the string is in locale specific encoding or - - if(*uptr < - - *mptr = - - -} - -/* - * NAME: ucs4->utf8duplicate() - * DESCRIPTION: duplicate and encode a ucs4 string into utf8 - */ -id3_utf8_t *id3_ucs4_multibyteduplicate(id3_ucs4_t const *ucs4) -{ - id3_latin1_t *multi; - multi = malloc(id3_ucs4_multibytesize(ucs4) * sizeof(*utf8)); - if (multi) - id3_multibyte_encode(multi, ucs4); - - return release(multi); -} -#endif - -/* - * NAME: ucs4->copy() - * DESCRIPTION: copy a ucs4 string - */ -void id3_ucs4_copy(id3_ucs4_t *dest, id3_ucs4_t const *src) -{ - while ((*dest++ = *src++)) - ; -} - -/* - * NAME: ucs4->duplicate() - * DESCRIPTION: duplicate a ucs4 string - */ -id3_ucs4_t *id3_ucs4_duplicate(id3_ucs4_t const *src) -{ - id3_ucs4_t *ucs4; - - ucs4 = malloc(id3_ucs4_size(src) * sizeof(*ucs4)); - if (ucs4) - id3_ucs4_copy(ucs4, src); - - return ucs4; -} - -/* - * NAME: ucs4->putnumber() - * DESCRIPTION: write a ucs4 string containing a (positive) decimal number - */ -void id3_ucs4_putnumber(id3_ucs4_t *ucs4, unsigned long number) -{ - int digits[10], *digit; - - digit = digits; - - do { - *digit++ = number % 10; - number /= 10; - } - while (number); - - while (digit != digits) - *ucs4++ = '0' + *--digit; - - *ucs4 = 0; -} - -/* - * NAME: ucs4->getnumber() - * DESCRIPTION: read a ucs4 string containing a (positive) decimal number - */ -unsigned long id3_ucs4_getnumber(id3_ucs4_t const *ucs4) -{ - unsigned long number = 0; - - while (*ucs4 >= '0' && *ucs4 <= '9') - number = 10 * number + (*ucs4++ - '0'); - - return number; -} diff --git a/src/libid3tag/ucs4.h b/src/libid3tag/ucs4.h deleted file mode 100644 index bfb325d..0000000 --- a/src/libid3tag/ucs4.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: ucs4.h,v 1.11 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_UCS4_H -# define LIBID3TAG_UCS4_H - -# include "id3tag.h" - -# define ID3_UCS4_REPLACEMENTCHAR 0x000000b7L /* middle dot */ - -extern id3_ucs4_t const id3_ucs4_empty[]; - -id3_length_t id3_ucs4_length(id3_ucs4_t const *); -id3_length_t id3_ucs4_size(id3_ucs4_t const *); - -id3_length_t id3_ucs4_latin1size(id3_ucs4_t const *); -id3_length_t id3_ucs4_utf16size(id3_ucs4_t const *); -id3_length_t id3_ucs4_utf8size(id3_ucs4_t const *); - -void id3_ucs4_copy(id3_ucs4_t *, id3_ucs4_t const *); -id3_ucs4_t *id3_ucs4_duplicate(id3_ucs4_t const *); - -# endif diff --git a/src/libid3tag/utf16.c b/src/libid3tag/utf16.c deleted file mode 100644 index 70ee9d5..0000000 --- a/src/libid3tag/utf16.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: utf16.c,v 1.9 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <stdlib.h> - -# include "id3tag.h" -# include "utf16.h" -# include "ucs4.h" - -/* - * NAME: utf16->length() - * DESCRIPTION: return the number of ucs4 chars represented by a utf16 string - */ -id3_length_t id3_utf16_length(id3_utf16_t const *utf16) -{ - id3_length_t length = 0; - - while (*utf16) { - if (utf16[0] < 0xd800 || utf16[0] > 0xdfff) - ++length; - else if (utf16[0] >= 0xd800 && utf16[0] <= 0xdbff && - utf16[1] >= 0xdc00 && utf16[1] <= 0xdfff) { - ++length; - ++utf16; - } - - ++utf16; - } - - return length; -} - -/* - * NAME: utf16->size() - * DESCRIPTION: return the encoding size of a utf16 string - */ -id3_length_t id3_utf16_size(id3_utf16_t const *utf16) -{ - id3_utf16_t const *ptr = utf16; - - while (*ptr) - ++ptr; - - return ptr - utf16 + 1; -} - -/* - * NAME: utf16->ucs4duplicate() - * DESCRIPTION: duplicate and decode a utf16 string into ucs4 - */ -id3_ucs4_t *id3_utf16_ucs4duplicate(id3_utf16_t const *utf16) -{ - id3_ucs4_t *ucs4; - - ucs4 = malloc((id3_utf16_length(utf16) + 1) * sizeof(*ucs4)); - if (ucs4) - id3_utf16_decode(utf16, ucs4); - - return release(ucs4); -} - -/* - * NAME: utf16->decodechar() - * DESCRIPTION: decode a series of utf16 chars into a single ucs4 char - */ -id3_length_t id3_utf16_decodechar(id3_utf16_t const *utf16, id3_ucs4_t *ucs4) -{ - id3_utf16_t const *start = utf16; - - while (1) { - if (utf16[0] < 0xd800 || utf16[0] > 0xdfff) { - *ucs4 = utf16[0]; - return utf16 - start + 1; - } - else if (utf16[0] >= 0xd800 && utf16[0] <= 0xdbff && - utf16[1] >= 0xdc00 && utf16[1] <= 0xdfff) { - *ucs4 = (((utf16[0] & 0x03ffL) << 10) | - ((utf16[1] & 0x03ffL) << 0)) + 0x00010000L; - return utf16 - start + 2; - } - - ++utf16; - } -} - -/* - * NAME: utf16->encodechar() - * DESCRIPTION: encode a single ucs4 char into a series of up to 2 utf16 chars - */ -id3_length_t id3_utf16_encodechar(id3_utf16_t *utf16, id3_ucs4_t ucs4) -{ - if (ucs4 < 0x00010000L) { - utf16[0] = ucs4; - - return 1; - } - else if (ucs4 < 0x00110000L) { - ucs4 -= 0x00010000L; - - utf16[0] = ((ucs4 >> 10) & 0x3ff) | 0xd800; - utf16[1] = ((ucs4 >> 0) & 0x3ff) | 0xdc00; - - return 2; - } - - /* default */ - - return id3_utf16_encodechar(utf16, ID3_UCS4_REPLACEMENTCHAR); -} - -/* - * NAME: utf16->decode() - * DESCRIPTION: decode a complete utf16 string into a ucs4 string - */ -void id3_utf16_decode(id3_utf16_t const *utf16, id3_ucs4_t *ucs4) -{ - do - utf16 += id3_utf16_decodechar(utf16, ucs4); - while (*ucs4++); -} - -/* - * NAME: utf16->encode() - * DESCRIPTION: encode a complete ucs4 string into a utf16 string - */ -void id3_utf16_encode(id3_utf16_t *utf16, id3_ucs4_t const *ucs4) -{ - do - utf16 += id3_utf16_encodechar(utf16, *ucs4); - while (*ucs4++); -} - -/* - * NAME: utf16->put() - * DESCRIPTION: serialize a single utf16 character - */ -id3_length_t id3_utf16_put(id3_byte_t **ptr, id3_utf16_t utf16, - enum id3_utf16_byteorder byteorder) -{ - if (ptr) { - switch (byteorder) { - default: - case ID3_UTF16_BYTEORDER_BE: - (*ptr)[0] = (utf16 >> 8) & 0xff; - (*ptr)[1] = (utf16 >> 0) & 0xff; - break; - - case ID3_UTF16_BYTEORDER_LE: - (*ptr)[0] = (utf16 >> 0) & 0xff; - (*ptr)[1] = (utf16 >> 8) & 0xff; - break; - } - - *ptr += 2; - } - - return 2; -} - -/* - * NAME: utf16->get() - * DESCRIPTION: deserialize a single utf16 character - */ -id3_utf16_t id3_utf16_get(id3_byte_t const **ptr, - enum id3_utf16_byteorder byteorder) -{ - id3_utf16_t utf16; - - switch (byteorder) { - default: - case ID3_UTF16_BYTEORDER_BE: - utf16 = - ((*ptr)[0] << 8) | - ((*ptr)[1] << 0); - break; - - case ID3_UTF16_BYTEORDER_LE: - utf16 = - ((*ptr)[0] << 0) | - ((*ptr)[1] << 8); - break; - } - - *ptr += 2; - - return utf16; -} - -/* - * NAME: utf16->serialize() - * DESCRIPTION: serialize a ucs4 string using utf16 encoding - */ -id3_length_t id3_utf16_serialize(id3_byte_t **ptr, id3_ucs4_t const *ucs4, - enum id3_utf16_byteorder byteorder, - int terminate) -{ - id3_length_t size = 0; - id3_utf16_t utf16[2], *out; - - if (byteorder == ID3_UTF16_BYTEORDER_ANY) - size += id3_utf16_put(ptr, 0xfeff, byteorder); - - while (*ucs4) { - switch (id3_utf16_encodechar(out = utf16, *ucs4++)) { - case 2: size += id3_utf16_put(ptr, *out++, byteorder); - case 1: size += id3_utf16_put(ptr, *out++, byteorder); - case 0: break; - } - } - - if (terminate) - size += id3_utf16_put(ptr, 0, byteorder); - - return size; -} - -/* - * NAME: utf16->deserialize() - * DESCRIPTION: deserialize a ucs4 string using utf16 encoding - */ -id3_ucs4_t *id3_utf16_deserialize(id3_byte_t const **ptr, id3_length_t length, - enum id3_utf16_byteorder byteorder) -{ - id3_byte_t const *end; - id3_utf16_t *utf16ptr, *utf16; - id3_ucs4_t *ucs4; - - end = *ptr + (length & ~1); - - utf16 = malloc((length / 2 + 1) * sizeof(*utf16)); - if (utf16 == 0) - return 0; - - if (byteorder == ID3_UTF16_BYTEORDER_ANY && end - *ptr > 0) { - switch (((*ptr)[0] << 8) | - ((*ptr)[1] << 0)) { - case 0xfeff: - byteorder = ID3_UTF16_BYTEORDER_BE; - *ptr += 2; - break; - - case 0xfffe: - byteorder = ID3_UTF16_BYTEORDER_LE; - *ptr += 2; - break; - } - } - - utf16ptr = utf16; - while (end - *ptr > 0 && (*utf16ptr = id3_utf16_get(ptr, byteorder))) - ++utf16ptr; - - *utf16ptr = 0; - - ucs4 = malloc((id3_utf16_length(utf16) + 1) * sizeof(*ucs4)); - if (ucs4) - id3_utf16_decode(utf16, ucs4); - - free(utf16); - - return ucs4; -} diff --git a/src/libid3tag/utf16.h b/src/libid3tag/utf16.h deleted file mode 100644 index b7be49c..0000000 --- a/src/libid3tag/utf16.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: utf16.h,v 1.8 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_UTF16_H -# define LIBID3TAG_UTF16_H - -# include "id3tag.h" - -enum id3_utf16_byteorder { - ID3_UTF16_BYTEORDER_ANY, - ID3_UTF16_BYTEORDER_BE, - ID3_UTF16_BYTEORDER_LE -}; - -id3_length_t id3_utf16_length(id3_utf16_t const *); -id3_length_t id3_utf16_size(id3_utf16_t const *); - -id3_length_t id3_utf16_decodechar(id3_utf16_t const *, id3_ucs4_t *); -id3_length_t id3_utf16_encodechar(id3_utf16_t *, id3_ucs4_t); - -void id3_utf16_decode(id3_utf16_t const *, id3_ucs4_t *); -void id3_utf16_encode(id3_utf16_t *, id3_ucs4_t const *); - -id3_length_t id3_utf16_put(id3_byte_t **, id3_utf16_t, - enum id3_utf16_byteorder); -id3_utf16_t id3_utf16_get(id3_byte_t const **, enum id3_utf16_byteorder); - -id3_length_t id3_utf16_serialize(id3_byte_t **, id3_ucs4_t const *, - enum id3_utf16_byteorder, int); -id3_ucs4_t *id3_utf16_deserialize(id3_byte_t const **, id3_length_t, - enum id3_utf16_byteorder); - -# endif diff --git a/src/libid3tag/utf8.c b/src/libid3tag/utf8.c deleted file mode 100644 index 4d8649a..0000000 --- a/src/libid3tag/utf8.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: utf8.c,v 1.9 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <stdlib.h> - -# include "id3tag.h" -# include "utf8.h" -# include "ucs4.h" - -/* - * NAME: utf8->length() - * DESCRIPTION: return the number of ucs4 chars represented by a utf8 string - */ -id3_length_t id3_utf8_length(id3_utf8_t const *utf8) -{ - id3_length_t length = 0; - - while (*utf8) { - if ((utf8[0] & 0x80) == 0x00) - ++length; - else if ((utf8[0] & 0xe0) == 0xc0 && - (utf8[1] & 0xc0) == 0x80) { - if (((utf8[0] & 0x1fL) << 6) >= 0x00000080L) { - ++length; - utf8 += 1; - } - } - else if ((utf8[0] & 0xf0) == 0xe0 && - (utf8[1] & 0xc0) == 0x80 && - (utf8[2] & 0xc0) == 0x80) { - if ((((utf8[0] & 0x0fL) << 12) | - ((utf8[1] & 0x3fL) << 6)) >= 0x00000800L) { - ++length; - utf8 += 2; - } - } - else if ((utf8[0] & 0xf8) == 0xf0 && - (utf8[1] & 0xc0) == 0x80 && - (utf8[2] & 0xc0) == 0x80 && - (utf8[3] & 0xc0) == 0x80) { - if ((((utf8[0] & 0x07L) << 18) | - ((utf8[1] & 0x3fL) << 12)) >= 0x00010000L) { - ++length; - utf8 += 3; - } - } - else if ((utf8[0] & 0xfc) == 0xf8 && - (utf8[1] & 0xc0) == 0x80 && - (utf8[2] & 0xc0) == 0x80 && - (utf8[3] & 0xc0) == 0x80 && - (utf8[4] & 0xc0) == 0x80) { - if ((((utf8[0] & 0x03L) << 24) | - ((utf8[0] & 0x3fL) << 18)) >= 0x00200000L) { - ++length; - utf8 += 4; - } - } - else if ((utf8[0] & 0xfe) == 0xfc && - (utf8[1] & 0xc0) == 0x80 && - (utf8[2] & 0xc0) == 0x80 && - (utf8[3] & 0xc0) == 0x80 && - (utf8[4] & 0xc0) == 0x80 && - (utf8[5] & 0xc0) == 0x80) { - if ((((utf8[0] & 0x01L) << 30) | - ((utf8[0] & 0x3fL) << 24)) >= 0x04000000L) { - ++length; - utf8 += 5; - } - } - - ++utf8; - } - - return length; -} - -/* - * NAME: utf8->size() - * DESCRIPTION: return the encoding size of a utf8 string - */ -id3_length_t id3_utf8_size(id3_utf8_t const *utf8) -{ - id3_utf8_t const *ptr = utf8; - - while (*ptr) - ++ptr; - - return ptr - utf8 + 1; -} - -/* - * NAME: utf8->ucs4duplicate() - * DESCRIPTION: duplicate and decode a utf8 string into ucs4 - */ -id3_ucs4_t *id3_utf8_ucs4duplicate(id3_utf8_t const *utf8) -{ - id3_ucs4_t *ucs4; - - ucs4 = malloc((id3_utf8_length(utf8) + 1) * sizeof(*ucs4)); - if (ucs4) - id3_utf8_decode(utf8, ucs4); - - return release(ucs4); -} - -/* - * NAME: utf8->decodechar() - * DESCRIPTION: decode a series of utf8 chars into a single ucs4 char - */ -id3_length_t id3_utf8_decodechar(id3_utf8_t const *utf8, id3_ucs4_t *ucs4) -{ - id3_utf8_t const *start = utf8; - - while (1) { - if ((utf8[0] & 0x80) == 0x00) { - *ucs4 = utf8[0]; - return utf8 - start + 1; - } - else if ((utf8[0] & 0xe0) == 0xc0 && - (utf8[1] & 0xc0) == 0x80) { - *ucs4 = - ((utf8[0] & 0x1fL) << 6) | - ((utf8[1] & 0x3fL) << 0); - if (*ucs4 >= 0x00000080L) - return utf8 - start + 2; - } - else if ((utf8[0] & 0xf0) == 0xe0 && - (utf8[1] & 0xc0) == 0x80 && - (utf8[2] & 0xc0) == 0x80) { - *ucs4 = - ((utf8[0] & 0x0fL) << 12) | - ((utf8[1] & 0x3fL) << 6) | - ((utf8[2] & 0x3fL) << 0); - if (*ucs4 >= 0x00000800L) - return utf8 - start + 3; - } - else if ((utf8[0] & 0xf8) == 0xf0 && - (utf8[1] & 0xc0) == 0x80 && - (utf8[2] & 0xc0) == 0x80 && - (utf8[3] & 0xc0) == 0x80) { - *ucs4 = - ((utf8[0] & 0x07L) << 18) | - ((utf8[1] & 0x3fL) << 12) | - ((utf8[2] & 0x3fL) << 6) | - ((utf8[3] & 0x3fL) << 0); - if (*ucs4 >= 0x00010000L) - return utf8 - start + 4; - } - else if ((utf8[0] & 0xfc) == 0xf8 && - (utf8[1] & 0xc0) == 0x80 && - (utf8[2] & 0xc0) == 0x80 && - (utf8[3] & 0xc0) == 0x80 && - (utf8[4] & 0xc0) == 0x80) { - *ucs4 = - ((utf8[0] & 0x03L) << 24) | - ((utf8[1] & 0x3fL) << 18) | - ((utf8[2] & 0x3fL) << 12) | - ((utf8[3] & 0x3fL) << 6) | - ((utf8[4] & 0x3fL) << 0); - if (*ucs4 >= 0x00200000L) - return utf8 - start + 5; - } - else if ((utf8[0] & 0xfe) == 0xfc && - (utf8[1] & 0xc0) == 0x80 && - (utf8[2] & 0xc0) == 0x80 && - (utf8[3] & 0xc0) == 0x80 && - (utf8[4] & 0xc0) == 0x80 && - (utf8[5] & 0xc0) == 0x80) { - *ucs4 = - ((utf8[0] & 0x01L) << 30) | - ((utf8[1] & 0x3fL) << 24) | - ((utf8[2] & 0x3fL) << 18) | - ((utf8[3] & 0x3fL) << 12) | - ((utf8[4] & 0x3fL) << 6) | - ((utf8[5] & 0x3fL) << 0); - if (*ucs4 >= 0x04000000L) - return utf8 - start + 6; - } - - ++utf8; - } -} - -/* - * NAME: utf8->encodechar() - * DESCRIPTION: encode a single ucs4 char into a series of up to 6 utf8 chars - */ -id3_length_t id3_utf8_encodechar(id3_utf8_t *utf8, id3_ucs4_t ucs4) -{ - if (ucs4 <= 0x0000007fL) { - utf8[0] = ucs4; - - return 1; - } - else if (ucs4 <= 0x000007ffL) { - utf8[0] = 0xc0 | ((ucs4 >> 6) & 0x1f); - utf8[1] = 0x80 | ((ucs4 >> 0) & 0x3f); - - return 2; - } - else if (ucs4 <= 0x0000ffffL) { - utf8[0] = 0xe0 | ((ucs4 >> 12) & 0x0f); - utf8[1] = 0x80 | ((ucs4 >> 6) & 0x3f); - utf8[2] = 0x80 | ((ucs4 >> 0) & 0x3f); - - return 3; - } - else if (ucs4 <= 0x001fffffL) { - utf8[0] = 0xf0 | ((ucs4 >> 18) & 0x07); - utf8[1] = 0x80 | ((ucs4 >> 12) & 0x3f); - utf8[2] = 0x80 | ((ucs4 >> 6) & 0x3f); - utf8[3] = 0x80 | ((ucs4 >> 0) & 0x3f); - - return 4; - } - else if (ucs4 <= 0x03ffffffL) { - utf8[0] = 0xf8 | ((ucs4 >> 24) & 0x03); - utf8[1] = 0x80 | ((ucs4 >> 18) & 0x3f); - utf8[2] = 0x80 | ((ucs4 >> 12) & 0x3f); - utf8[3] = 0x80 | ((ucs4 >> 6) & 0x3f); - utf8[4] = 0x80 | ((ucs4 >> 0) & 0x3f); - - return 5; - } - else if (ucs4 <= 0x7fffffffL) { - utf8[0] = 0xfc | ((ucs4 >> 30) & 0x01); - utf8[1] = 0x80 | ((ucs4 >> 24) & 0x3f); - utf8[2] = 0x80 | ((ucs4 >> 18) & 0x3f); - utf8[3] = 0x80 | ((ucs4 >> 12) & 0x3f); - utf8[4] = 0x80 | ((ucs4 >> 6) & 0x3f); - utf8[5] = 0x80 | ((ucs4 >> 0) & 0x3f); - - return 6; - } - - /* default */ - - return id3_utf8_encodechar(utf8, ID3_UCS4_REPLACEMENTCHAR); -} - -/* - * NAME: utf8->decode() - * DESCRIPTION: decode a complete utf8 string into a ucs4 string - */ -void id3_utf8_decode(id3_utf8_t const *utf8, id3_ucs4_t *ucs4) -{ - do - utf8 += id3_utf8_decodechar(utf8, ucs4); - while (*ucs4++); -} - -/* - * NAME: utf8->encode() - * DESCRIPTION: encode a complete ucs4 string into a utf8 string - */ -void id3_utf8_encode(id3_utf8_t *utf8, id3_ucs4_t const *ucs4) -{ - do - utf8 += id3_utf8_encodechar(utf8, *ucs4); - while (*ucs4++); -} - -/* - * NAME: utf8->put() - * DESCRIPTION: serialize a single utf8 character - */ -id3_length_t id3_utf8_put(id3_byte_t **ptr, id3_utf8_t utf8) -{ - if (ptr) - *(*ptr)++ = utf8; - - return 1; -} - -/* - * NAME: utf8->get() - * DESCRIPTION: deserialize a single utf8 character - */ -id3_utf8_t id3_utf8_get(id3_byte_t const **ptr) -{ - return *(*ptr)++; -} - -/* - * NAME: utf8->serialize() - * DESCRIPTION: serialize a ucs4 string using utf8 encoding - */ -id3_length_t id3_utf8_serialize(id3_byte_t **ptr, id3_ucs4_t const *ucs4, - int terminate) -{ - id3_length_t size = 0; - id3_utf8_t utf8[6], *out; - - while (*ucs4) { - switch (id3_utf8_encodechar(out = utf8, *ucs4++)) { - case 6: size += id3_utf8_put(ptr, *out++); - case 5: size += id3_utf8_put(ptr, *out++); - case 4: size += id3_utf8_put(ptr, *out++); - case 3: size += id3_utf8_put(ptr, *out++); - case 2: size += id3_utf8_put(ptr, *out++); - case 1: size += id3_utf8_put(ptr, *out++); - case 0: break; - } - } - - if (terminate) - size += id3_utf8_put(ptr, 0); - - return size; -} - -/* - * NAME: utf8->deserialize() - * DESCRIPTION: deserialize a ucs4 string using utf8 encoding - */ -id3_ucs4_t *id3_utf8_deserialize(id3_byte_t const **ptr, id3_length_t length) -{ - id3_byte_t const *end; - id3_utf8_t *utf8ptr, *utf8; - id3_ucs4_t *ucs4; - - end = *ptr + length; - - utf8 = malloc((length + 1) * sizeof(*utf8)); - if (utf8 == 0) - return 0; - - utf8ptr = utf8; - while (end - *ptr > 0 && (*utf8ptr = id3_utf8_get(ptr))) - ++utf8ptr; - - *utf8ptr = 0; - - ucs4 = malloc((id3_utf8_length(utf8) + 1) * sizeof(*ucs4)); - if (ucs4) - id3_utf8_decode(utf8, ucs4); - - free(utf8); - - return ucs4; -} diff --git a/src/libid3tag/utf8.h b/src/libid3tag/utf8.h deleted file mode 100644 index 572bb2a..0000000 --- a/src/libid3tag/utf8.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: utf8.h,v 1.7 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_UTF8_H -# define LIBID3TAG_UTF8_H - -# include "id3tag.h" - -id3_length_t id3_utf8_length(id3_utf8_t const *); -id3_length_t id3_utf8_size(id3_utf8_t const *); - -id3_length_t id3_utf8_decodechar(id3_utf8_t const *, id3_ucs4_t *); -id3_length_t id3_utf8_encodechar(id3_utf8_t *, id3_ucs4_t); - -void id3_utf8_decode(id3_utf8_t const *, id3_ucs4_t *); -void id3_utf8_encode(id3_utf8_t *, id3_ucs4_t const *); - -id3_length_t id3_utf8_put(id3_byte_t **, id3_utf8_t); -id3_utf8_t id3_utf8_get(id3_byte_t const **); - -id3_length_t id3_utf8_serialize(id3_byte_t **, id3_ucs4_t const *, int); -id3_ucs4_t *id3_utf8_deserialize(id3_byte_t const **, id3_length_t); - -# endif diff --git a/src/libid3tag/util.c b/src/libid3tag/util.c deleted file mode 100644 index 61ccccf..0000000 --- a/src/libid3tag/util.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: util.c,v 1.9 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include <stdlib.h> -# include <zlib.h> - -# include "id3tag.h" -# include "util.h" - -/* - * NAME: util->unsynchronise() - * DESCRIPTION: perform (in-place) unsynchronisation - */ -id3_length_t id3_util_unsynchronise(id3_byte_t *data, id3_length_t length) -{ - id3_length_t bytes = 0, count; - id3_byte_t *end = data + length; - id3_byte_t const *ptr; - - if (length == 0) - return 0; - - for (ptr = data; ptr < end - 1; ++ptr) { - if (ptr[0] == 0xff && (ptr[1] == 0x00 || (ptr[1] & 0xe0) == 0xe0)) - ++bytes; - } - - if (bytes) { - ptr = end; - end += bytes; - - *--end = *--ptr; - - for (count = bytes; count; *--end = *--ptr) { - if (ptr[-1] == 0xff && (ptr[0] == 0x00 || (ptr[0] & 0xe0) == 0xe0)) { - *--end = 0x00; - --count; - } - } - } - - return length + bytes; -} - -/* - * NAME: util->deunsynchronise() - * DESCRIPTION: undo unsynchronisation (in-place) - */ -id3_length_t id3_util_deunsynchronise(id3_byte_t *data, id3_length_t length) -{ - id3_byte_t const *old, *end = data + length; - id3_byte_t *new; - - if (length == 0) - return 0; - - for (old = new = data; old < end - 1; ++old) { - *new++ = *old; - if (old[0] == 0xff && old[1] == 0x00) - ++old; - } - - *new++ = *old; - - return new - data; -} - -/* - * NAME: util->compress() - * DESCRIPTION: perform zlib deflate method compression - */ -id3_byte_t *id3_util_compress(id3_byte_t const *data, id3_length_t length, - id3_length_t *newlength) -{ - id3_byte_t *compressed; - - *newlength = length + 12; - *newlength += *newlength / 1000; - - compressed = malloc(*newlength); - if (compressed) { - if (compress2(compressed, newlength, data, length, - Z_BEST_COMPRESSION) != Z_OK || - *newlength >= length) { - free(compressed); - compressed = 0; - } - else { - id3_byte_t *resized; - - resized = realloc(compressed, *newlength ? *newlength : 1); - if (resized) - compressed = resized; - } - } - - return compressed; -} - -/* - * NAME: util->decompress() - * DESCRIPTION: undo zlib deflate method compression - */ -id3_byte_t *id3_util_decompress(id3_byte_t const *data, id3_length_t length, - id3_length_t newlength) -{ - id3_byte_t *decompressed; - - decompressed = malloc(newlength ? newlength : 1); - if (decompressed) { - id3_length_t size; - - size = newlength; - - if (uncompress(decompressed, &size, data, length) != Z_OK || - size != newlength) { - free(decompressed); - decompressed = 0; - } - } - - return decompressed; -} diff --git a/src/libid3tag/util.h b/src/libid3tag/util.h deleted file mode 100644 index 4b895d2..0000000 --- a/src/libid3tag/util.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: util.h,v 1.6 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_UTIL_H -# define LIBID3TAG_UTIL_H - -# include "id3tag.h" - -id3_length_t id3_util_unsynchronise(id3_byte_t *, id3_length_t); -id3_length_t id3_util_deunsynchronise(id3_byte_t *, id3_length_t); - -id3_byte_t *id3_util_compress(id3_byte_t const *, id3_length_t, - id3_length_t *); -id3_byte_t *id3_util_decompress(id3_byte_t const *, id3_length_t, - id3_length_t); - -# endif diff --git a/src/libid3tag/version.c b/src/libid3tag/version.c deleted file mode 100644 index d54b80a..0000000 --- a/src/libid3tag/version.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: version.c,v 1.7 2004/01/23 09:41:32 rob Exp $ - */ - -# ifdef HAVE_CONFIG_H -# include "config.h" -# endif - -# include "global.h" - -# include "id3tag.h" -# include "version.h" - -char const id3_version[] = "ID3 Tag Library " ID3_VERSION; -char const id3_copyright[] = "Copyright (C) " ID3_PUBLISHYEAR " " ID3_AUTHOR; -char const id3_author[] = ID3_AUTHOR " <" ID3_EMAIL ">"; - -char const id3_build[] = "" -# if defined(DEBUG) - "DEBUG " -# elif defined(NDEBUG) - "NDEBUG " -# endif - -# if defined(EXPERIMENTAL) - "EXPERIMENTAL " -# endif -; diff --git a/src/libid3tag/version.h b/src/libid3tag/version.h deleted file mode 100644 index 5eaa11f..0000000 --- a/src/libid3tag/version.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * libid3tag - ID3 tag manipulation library - * Copyright (C) 2000-2004 Underbit Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * $Id: version.h,v 1.7 2004/01/23 09:41:32 rob Exp $ - */ - -# ifndef LIBID3TAG_VERSION_H -# define LIBID3TAG_VERSION_H - -# endif diff --git a/src/tests/Makefile b/src/tests/Makefile deleted file mode 100644 index d37480d..0000000 --- a/src/tests/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -include ../../buildsys.mk -include ../../extra.mk - -OBJECTIVE_LIBS_NOINST = tuple_formatter_test \ - tuple_formatter_functor_test \ - tag_wma_test - -LDFLAGS += $(AUDLDFLAGS) -LDADD = \ - $(DBUS_LIBS) \ - $(GTK_LIBS) \ - $(MOWGLI_LIBS) - -CFLAGS += \ - $(GTK_CFLAGS) \ - $(DBUS_CFLAGS) \ - $(AUDACIOUS_DEFINES) \ - $(ARCH_DEFINES) \ - $(MOWGLI_CFLAGS) \ - -I.. -I../.. \ - -I../intl -I../audacious - - -AUDCORE_OBJS = ../libaudcore/tuple.o ../libaudcore/tuple_formatter.o \ - ../libaudcore/audstrings.o ../libaudcore/tuple_compiler.o - -AUDTAG_OBJS = ../libaudtag/util.o ../libaudtag/wma/guid.o \ - ../libaudtag/wma/wma.o ../libaudtag/wma/wma_fmt.o - -COMMON_OBJS = test_harness.o $(AUDCORE_OBJS) - -TFT_OBJS = $(COMMON_OBJS) tuple_formatter_test.o - -tuple_formatter_test: $(TFT_OBJS) - $(CC) $(LDFLAGS) $(TFT_OBJS) $(LDADD) -o $@ - @printf "%10s %-20s\n" LINK $@ - ./$@ - @printf "%10s %-20s\n" TEST-PASS $@ - -TFFT_OBJS = $(COMMON_OBJS) tuple_formatter_functor_test.o -tuple_formatter_functor_test: $(TFFT_OBJS) - $(CC) $(LDFLAGS) $(TFFT_OBJS) $(LDADD) -o $@ - @printf "%10s %-20s\n" LINK $@ - ./$@ - @printf "%10s %-20s\n" TEST-PASS $@ - -TAG_WMA_OBJS = $(COMMON_OBJS) $(AUDTAG_OBJS) tag_wma_test.o -tag_wma_test: $(TAG_WMA_OBJS) - $(CC) $(LDFLAGS) $(TAG_WMA_OBJS) $(LDADD) -o $@ -laudcore - @printf "%10s %-20s\n" LINK $@ - ./$@ - @printf "%10s %-20s\n" TEST-PASS $@ - - diff --git a/src/tests/README b/src/tests/README deleted file mode 100644 index 67adc5d..0000000 --- a/src/tests/README +++ /dev/null @@ -1,11 +0,0 @@ -This directory contains some tests. To run them, type "make". - -Any needed uncompiled files in the audacious core will be compiled -with the proper CFLAGS. Don't worry about that. - -You can help make this directory more useful by writing tests as -you fix bugs. Unless they're in the UI, autotesting that may be -problematic. - -To write a test, simply edit an existing test and the Makefile -as required. diff --git a/src/tests/tag_wma_test.c b/src/tests/tag_wma_test.c deleted file mode 100644 index 6690e0d..0000000 --- a/src/tests/tag_wma_test.c +++ /dev/null @@ -1,98 +0,0 @@ -#include <glib.h> -#include <libaudcore/tuple.h> -#define TEST -#include <libaudtag/util.h> -#include <libaudtag/wma/wma.h> - -#define WMA1_FILE "test_wma1.wma" -#define WMA1_FILE_OUT "test_wma1_out.wma" -#define WMA2_FILE "test_wma2.wma" - -int test_read(int n, char* f) { - - Tuple * test_tuple; - test_tuple = tuple_new(); - - tuple_associate_string(test_tuple, FIELD_FILE_PATH, NULL, f); - - test_tuple = wma_populate_tuple_from_file(test_tuple); - - const char *file_path = tuple_get_string(test_tuple, FIELD_FILE_PATH, NULL); - - if (g_ascii_strcasecmp(file_path, f)) { - g_print("tagging failure on test %d:\n" - "'%s' != '%s' \n", - n, file_path, f); - tuple_free(test_tuple); - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} - -int test_write(int n, char *f) { - - char *title = "Title 제목 ", - *author = "Author المؤلف", - *comment = "Comment Коментар", - *album = "Album 相冊", - *genre = "Genre शैली"; - Tuple * test_tuple = tuple_new(); - test_tuple = wma_populate_tuple_from_file(test_tuple); - - Tuple *write_test_tuple = makeTuple(test_tuple, - title, author, - comment, album, - genre, "2111", - f, 2); - - wma_write_tuple_to_file(write_test_tuple); - wma_populate_tuple_from_file(test_tuple); - - const char* title_new = tuple_get_string(test_tuple, FIELD_TITLE, NULL); - const char* author_new = tuple_get_string(test_tuple, FIELD_ARTIST, NULL); - const char* comment_new = tuple_get_string(test_tuple, FIELD_COMMENT, NULL); - const char* album_new = tuple_get_string(test_tuple, FIELD_ALBUM, NULL); - const char* genre_new = tuple_get_string(test_tuple, FIELD_GENRE, NULL); - - if (g_ascii_strcasecmp(title, title_new) || - g_ascii_strcasecmp(author, author_new) || - g_ascii_strcasecmp(comment, comment_new) || - g_ascii_strcasecmp(album, album_new) || - g_ascii_strcasecmp(genre, genre_new)) { - g_print("tagging failure on test %d:\n" - "'%s' != '%s' \n" - "'%s' != '%s' \n" - "'%s' != '%s' \n" - "'%s' != '%s' \n" - "'%s' != '%s' \n", - n, - title, title_new, - author, author_new, - comment, comment_new, - album, album_new, - genre, genre_new); - - tuple_free(test_tuple); - tuple_free(write_test_tuple); - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} - -int test_run(int argc, char *argv[]) { - - if (test_read(1, WMA1_FILE) == EXIT_FAILURE) - return EXIT_FAILURE; - - if (test_read(2, WMA2_FILE) == EXIT_FAILURE) - return EXIT_FAILURE; - - - if (test_write(3, WMA1_FILE) == EXIT_FAILURE) - return EXIT_FAILURE; - - if (test_write(4, WMA2_FILE) == EXIT_FAILURE) - return EXIT_FAILURE; - - return EXIT_SUCCESS; -} diff --git a/src/tests/test_harness.c b/src/tests/test_harness.c deleted file mode 100644 index 37fe7cf..0000000 --- a/src/tests/test_harness.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Audacious - * Copyright (c) 2007 William Pitcock - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses>. - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#include <glib.h> -#include <mowgli.h> - -extern int test_run(gint argc, const gchar *argv[]); - -int -main(gint argc, const gchar *argv[]) -{ - g_thread_init(NULL); - - mowgli_init(); - - if (!g_thread_supported()) - mowgli_log("Warning: GThread not supported. Some tests may fail."); - - return test_run(argc, argv); -} - diff --git a/src/tests/test_wma1.wma b/src/tests/test_wma1.wma Binary files differdeleted file mode 100644 index 4a33136..0000000 --- a/src/tests/test_wma1.wma +++ /dev/null diff --git a/src/tests/test_wma2.wma b/src/tests/test_wma2.wma Binary files differdeleted file mode 100644 index ece725d..0000000 --- a/src/tests/test_wma2.wma +++ /dev/null diff --git a/src/tests/tuple_formatter_functor_test.c b/src/tests/tuple_formatter_functor_test.c deleted file mode 100644 index 3a8d7fb..0000000 --- a/src/tests/tuple_formatter_functor_test.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Audacious - * Copyright (c) 2007 William Pitcock - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses>. - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#include <glib.h> -#include <mowgli.h> - -#include <libaudcore/tuple.h> -#include <libaudcore/tuple_formatter.h> - -static gboolean -test_functor(Tuple *tuple, const char *expr) -{ - return TRUE; -} - -int -test_run(int argc, const char *argv[]) -{ - Tuple *tuple; - gchar *tstr; - - tuple_formatter_register_expression("(true)", test_functor); - - tuple = tuple_new(); - tuple_associate_string(tuple, FIELD_ARTIST, "splork", "moo"); - - tstr = tuple_formatter_process_string(tuple, "${(true):${splork}}"); - if (g_ascii_strcasecmp(tstr, "moo")) - { - g_print("fail 1: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "%{audacious-version}"); - if (g_str_has_prefix(tstr, "audacious") == FALSE) - { - g_print("fail 2: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${(true):%{audacious-version}}"); - if (g_str_has_prefix(tstr, "audacious") == FALSE) - { - g_print("fail 3: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - mowgli_object_unref(tuple); - - return EXIT_SUCCESS; -} diff --git a/src/tests/tuple_formatter_test.c b/src/tests/tuple_formatter_test.c deleted file mode 100644 index febdf50..0000000 --- a/src/tests/tuple_formatter_test.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Audacious - * Copyright (c) 2007 William Pitcock - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses>. - * - * The Audacious team does not consider modular code linking to - * Audacious or using our public API to be a derived work. - */ - -#include <glib.h> -#include <mowgli.h> - -#include <libaudcore/tuple.h> -#include <libaudcore/tuple_formatter.h> - -int -test_run(int argc, const char *argv[]) -{ - Tuple *tuple; - gchar *tstr; - - tuple = tuple_new(); - tuple_associate_string(tuple, FIELD_ARTIST, "splork", "moo"); - tuple_associate_int(tuple, FIELD_TRACK_NUMBER, "splorkerz", 42); - - tstr = tuple_formatter_process_string(tuple, "${splork} ${splorkerz}"); - if (g_ascii_strcasecmp(tstr, "moo 42")) - { - g_print("fail 1: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${?fizz:${splork}} ${splorkerz}"); - if (g_ascii_strcasecmp(tstr, " 42")) - { - g_print("fail 2: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${?splork:${splork}} ${splorkerz}"); - if (g_ascii_strcasecmp(tstr, "moo 42")) - { - g_print("fail 3: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${==splork,splork:fields given matched}"); - if (g_ascii_strcasecmp(tstr, "fields given matched")) - { - g_print("fail 4: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${==splork,splork:${splork}}"); - if (g_ascii_strcasecmp(tstr, "moo")) - { - g_print("fail 5: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${!=splork,splorkerz:fields did not match}"); - if (g_ascii_strcasecmp(tstr, "fields did not match")) - { - g_print("fail 6: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${!=splork,splorkerz:${splorkerz}}"); - if (g_ascii_strcasecmp(tstr, "42")) - { - g_print("fail 7: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${!=splork,splork:${splorkerz}}"); - if (g_ascii_strcasecmp(tstr, "")) - { - g_print("fail 8: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${(empty)?splorky:${splorkerz}}"); - if (g_ascii_strcasecmp(tstr, "42")) - { - g_print("fail 9: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${?splork:${splork} - }${splork}"); - if (g_ascii_strcasecmp(tstr, "moo - moo")) - { - g_print("fail 10: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${?splork:${?splork:${splork}} - }${splork}"); - if (g_ascii_strcasecmp(tstr, "moo - moo")) - { - g_print("fail 11: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${?splork:${splork} - }${?splork:${splork} - }${splork}"); - if (g_ascii_strcasecmp(tstr, "moo - moo - moo")) - { - g_print("fail 12: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tuple_associate_string(tuple, FIELD_ARTIST, "sheep", ""); - - tstr = tuple_formatter_process_string(tuple, "${?splork:${splork} - }${?sheep:${sheep} - }${splork}"); - if (g_ascii_strcasecmp(tstr, "moo - - moo")) - { - g_print("fail 13: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${?splork:${splork} - }${?sheep:${sheep} - }${splork}"); - if (g_ascii_strcasecmp(tstr, "moo - - moo")) - { - g_print("fail 14: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${==splork,\"moo\":const text field matches}"); - if (g_ascii_strcasecmp(tstr, "const text field matches")) - { - g_print("fail 15: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${==\"moo\",\"moo\":const text fields match}"); - if (g_ascii_strcasecmp(tstr, "const text fields match")) - { - g_print("fail 16: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${!=splork,\"muu\":const text field doesn't match}"); - if (g_ascii_strcasecmp(tstr, "const text field doesn't match")) - { - g_print("fail 17: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - tstr = tuple_formatter_process_string(tuple, "${!=\"moo\",\"muu\":const text fields do not match}"); - if (g_ascii_strcasecmp(tstr, "const text fields do not match")) - { - g_print("fail 18: '%s'\n", tstr); - return EXIT_FAILURE; - } - g_free(tstr); - - mowgli_object_unref(tuple); - - return EXIT_SUCCESS; -} |