Mercurial > audlegacy
diff src/audlegacy/tuple.c @ 4811:7bf7f83a217e
rename src/audacious src/audlegacy so that both audlegacy and audacious can coexist.
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Wed, 26 Nov 2008 00:44:56 +0900 |
parents | src/audacious/tuple.c@4eb5a651bbc4 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audlegacy/tuple.c Wed Nov 26 00:44:56 2008 +0900 @@ -0,0 +1,412 @@ +/* + * Audacious + * Copyright (c) 2006-2007 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 <mowgli.h> + +#include "tuple.h" +#include "strings.h" + +const TupleBasicType tuple_fields[FIELD_LAST] = { + { "artist", TUPLE_STRING }, + { "title", TUPLE_STRING }, + { "album", TUPLE_STRING }, + { "comment", TUPLE_STRING }, + { "genre", TUPLE_STRING }, + + { "track", TUPLE_STRING }, + { "track-number", TUPLE_INT }, + { "length", TUPLE_INT }, + { "year", TUPLE_INT }, + { "quality", TUPLE_STRING }, + + { "codec", TUPLE_STRING }, + { "file-name", TUPLE_STRING }, + { "file-path", TUPLE_STRING }, + { "file-ext", TUPLE_STRING }, + { "song-artist", TUPLE_STRING }, + + { "mtime", TUPLE_INT }, + { "formatter", TUPLE_STRING }, + { "performer", TUPLE_STRING }, + { "copyright", TUPLE_STRING }, + { "date", TUPLE_STRING }, + + { "subsong-id", TUPLE_INT }, + { "subsong-num", TUPLE_INT }, + { "mime-type", TUPLE_STRING }, + { "bitrate", TUPLE_INT }, +}; + +static mowgli_heap_t *tuple_heap = NULL; +static mowgli_heap_t *tuple_value_heap = NULL; +static mowgli_object_class_t tuple_klass; + + +#define TUPLE_LOCKING +//#define TUPLE_DEBUG + +#ifdef TUPLE_LOCKING +static GStaticRWLock tuple_rwlock = G_STATIC_RW_LOCK_INIT; +# ifdef TUPLE_DEBUG +# define TUPDEB(X) fprintf(stderr, "TUPLE_" X "(%s:%d)\n", __FUNCTION__, __LINE__) +# define TUPLE_LOCK_WRITE(XX) { TUPDEB("LOCK_WRITE"); g_static_rw_lock_writer_lock(&tuple_rwlock); } +# define TUPLE_UNLOCK_WRITE(XX) { TUPDEB("UNLOCK_WRITE"); g_static_rw_lock_writer_unlock(&tuple_rwlock); } +# define TUPLE_LOCK_READ(XX) { TUPDEB("LOCK_READ"); g_static_rw_lock_reader_lock(&tuple_rwlock); } +# define TUPLE_UNLOCK_READ(XX) { TUPDEB("UNLOCK_READ"); g_static_rw_lock_reader_unlock(&tuple_rwlock); } +# else +# define TUPLE_LOCK_WRITE(XX) g_static_rw_lock_writer_lock(&tuple_rwlock) +# define TUPLE_UNLOCK_WRITE(XX) g_static_rw_lock_writer_unlock(&tuple_rwlock) +# define TUPLE_LOCK_READ(XX) g_static_rw_lock_reader_lock(&tuple_rwlock) +# define TUPLE_UNLOCK_READ(XX) g_static_rw_lock_reader_unlock(&tuple_rwlock) +# endif +#else +# define TUPLE_LOCK_WRITE(XX) +# define TUPLE_UNLOCK_WRITE(XX) +# define TUPLE_LOCK_READ(XX) +# define TUPLE_UNLOCK_READ(XX) +#endif + +/* iterative destructor of tuple values. */ +static void +tuple_value_destroy(mowgli_dictionary_elem_t *delem, gpointer privdata) +{ + TupleValue *value = (TupleValue *) delem->data; + + if (value->type == TUPLE_STRING) + g_free(value->value.string); + + mowgli_heap_free(tuple_value_heap, value); +} + +static void +tuple_destroy(gpointer data) +{ + Tuple *tuple = (Tuple *) data; + gint i; + + TUPLE_LOCK_WRITE(); + mowgli_dictionary_destroy(tuple->dict, tuple_value_destroy, NULL); + + for (i = 0; i < FIELD_LAST; i++) + if (tuple->values[i]) { + TupleValue *value = tuple->values[i]; + + if (value->type == TUPLE_STRING) + g_free(value->value.string); + + mowgli_heap_free(tuple_value_heap, value); + } + + g_free(tuple->subtunes); + + mowgli_heap_free(tuple_heap, tuple); + TUPLE_UNLOCK_WRITE(); +} + +Tuple * +tuple_new(void) +{ + Tuple *tuple; + + TUPLE_LOCK_WRITE(); + + if (tuple_heap == NULL) + { + tuple_heap = mowgli_heap_create(sizeof(Tuple), 512, BH_NOW); + tuple_value_heap = mowgli_heap_create(sizeof(TupleValue), 1024, BH_NOW); + mowgli_object_class_init(&tuple_klass, "audacious.tuple", tuple_destroy, FALSE); + } + + /* FIXME: use mowgli_object_bless_from_class() in mowgli 0.4 + when it is released --nenolod */ + tuple = mowgli_heap_alloc(tuple_heap); + memset(tuple, 0, sizeof(Tuple)); + mowgli_object_init(mowgli_object(tuple), NULL, &tuple_klass, NULL); + + tuple->dict = mowgli_dictionary_create(g_ascii_strcasecmp); + + TUPLE_UNLOCK_WRITE(); + return tuple; +} + +static TupleValue * +tuple_associate_data(Tuple *tuple, const gint cnfield, const gchar *field, TupleValueType ftype); + +static gboolean +_tuple_associate_raw_string(Tuple *tuple, const gint nfield, const gchar *field, gchar *string) +{ + TupleValue *value; + + TUPLE_LOCK_WRITE(); + if ((value = tuple_associate_data(tuple, nfield, field, TUPLE_STRING)) == NULL) + return FALSE; + + value->value.string = string; + + TUPLE_UNLOCK_WRITE(); + return TRUE; +} + +Tuple * +tuple_new_from_filename(const gchar *filename) +{ + gchar *ext; + Tuple *tuple; + + g_return_val_if_fail(filename != NULL, NULL); + + tuple = tuple_new(); + g_return_val_if_fail(tuple != NULL, NULL); + + _tuple_associate_raw_string(tuple, FIELD_FILE_NAME, NULL, + uri_to_display_basename(filename)); + + _tuple_associate_raw_string(tuple, FIELD_FILE_PATH, NULL, + uri_to_display_basename(filename)); + + ext = strrchr(filename, '.'); + if (ext != NULL) { + ++ext; + _tuple_associate_raw_string(tuple, FIELD_FILE_EXT, NULL, + g_strdup(ext)); + } + + return tuple; +} + + +static gint tuple_get_nfield(const gchar *field) +{ + gint i; + for (i = 0; i < FIELD_LAST; i++) + if (!strcmp(field, tuple_fields[i].name)) + return i; + return -1; +} + + +static TupleValue * +tuple_associate_data(Tuple *tuple, const gint cnfield, const gchar *field, TupleValueType ftype) +{ + const gchar *tfield = field; + gint nfield = cnfield; + TupleValue *value = NULL; + + g_return_val_if_fail(tuple != NULL, NULL); + g_return_val_if_fail(cnfield < FIELD_LAST, NULL); + + /* Check for known fields */ + if (nfield < 0) { + nfield = tuple_get_nfield(field); + if (nfield >= 0) { + fprintf(stderr, "WARNING! FIELD_* not used for '%s'!\n", field); + } + } + + /* Check if field was known */ + if (nfield >= 0) { + tfield = tuple_fields[nfield].name; + value = tuple->values[nfield]; + + if (ftype != tuple_fields[nfield].type) { + /* FIXME! Convert values perhaps .. or not? */ + fprintf(stderr, "Invalid type for [%s](%d->%d), %d != %d\n", tfield, cnfield, nfield, ftype, tuple_fields[nfield].type); + //mowgli_throw_exception_val(audacious.tuple.invalid_type_request, 0); + TUPLE_UNLOCK_WRITE(); + return NULL; + } + } else { + value = mowgli_dictionary_retrieve(tuple->dict, tfield); + } + + if (value != NULL) { + /* Value exists, just delete old associated data */ + if (value->type == TUPLE_STRING) { + g_free(value->value.string); + value->value.string = NULL; + } + } else { + /* Allocate a new value */ + value = mowgli_heap_alloc(tuple_value_heap); + value->type = ftype; + if (nfield >= 0) + tuple->values[nfield] = value; + else + mowgli_dictionary_add(tuple->dict, tfield, value); + } + + return value; +} + +gboolean +tuple_associate_string(Tuple *tuple, const gint nfield, const gchar *field, const gchar *string) +{ + TupleValue *value; + + TUPLE_LOCK_WRITE(); + if ((value = tuple_associate_data(tuple, nfield, field, TUPLE_STRING)) == NULL) + return FALSE; + + if (string == NULL) + value->value.string = NULL; + else + value->value.string = str_to_utf8(string); + + TUPLE_UNLOCK_WRITE(); + return TRUE; +} + +gboolean +tuple_associate_int(Tuple *tuple, const gint nfield, const gchar *field, gint integer) +{ + TupleValue *value; + + TUPLE_LOCK_WRITE(); + if ((value = tuple_associate_data(tuple, nfield, field, TUPLE_INT)) == NULL) + return FALSE; + + value->value.integer = integer; + + TUPLE_UNLOCK_WRITE(); + return TRUE; +} + +void +tuple_disassociate(Tuple *tuple, const gint cnfield, const gchar *field) +{ + TupleValue *value; + gint nfield = cnfield; + + g_return_if_fail(tuple != NULL); + g_return_if_fail(nfield < FIELD_LAST); + + if (nfield < 0) + nfield = tuple_get_nfield(field); + + TUPLE_LOCK_WRITE(); + if (nfield < 0) + /* why _delete()? because _delete() returns the dictnode's data on success */ + value = mowgli_dictionary_delete(tuple->dict, field); + else { + value = tuple->values[nfield]; + tuple->values[nfield] = NULL; + } + + if (value == NULL) { + TUPLE_UNLOCK_WRITE(); + return; + } + + /* Free associated data */ + if (value->type == TUPLE_STRING) { + g_free(value->value.string); + value->value.string = NULL; + } + + mowgli_heap_free(tuple_value_heap, value); + TUPLE_UNLOCK_WRITE(); +} + +TupleValueType +tuple_get_value_type(Tuple *tuple, const gint cnfield, const gchar *field) +{ + TupleValueType type = TUPLE_UNKNOWN; + gint nfield = cnfield; + + g_return_val_if_fail(tuple != NULL, TUPLE_UNKNOWN); + g_return_val_if_fail(nfield < FIELD_LAST, TUPLE_UNKNOWN); + + if (nfield < 0) + nfield = tuple_get_nfield(field); + + TUPLE_LOCK_READ(); + if (nfield < 0) { + TupleValue *value; + if ((value = mowgli_dictionary_retrieve(tuple->dict, field)) != NULL) + type = value->type; + } else { + if (tuple->values[nfield]) + type = tuple->values[nfield]->type; + } + + TUPLE_UNLOCK_READ(); + return type; +} + +const gchar * +tuple_get_string(Tuple *tuple, const gint cnfield, const gchar *field) +{ + TupleValue *value; + gint nfield = cnfield; + + g_return_val_if_fail(tuple != NULL, NULL); + g_return_val_if_fail(nfield < FIELD_LAST, NULL); + + if (nfield < 0) + nfield = tuple_get_nfield(field); + + TUPLE_LOCK_READ(); + if (nfield < 0) + value = mowgli_dictionary_retrieve(tuple->dict, field); + else + value = tuple->values[nfield]; + + if (value) { + if (value->type != TUPLE_STRING) + mowgli_throw_exception_val(audacious.tuple.invalid_type_request, NULL); + + TUPLE_UNLOCK_READ(); + return value->value.string; + } else { + TUPLE_UNLOCK_READ(); + return NULL; + } +} + +gint +tuple_get_int(Tuple *tuple, const gint cnfield, const gchar *field) +{ + TupleValue *value; + gint nfield = cnfield; + + g_return_val_if_fail(tuple != NULL, 0); + g_return_val_if_fail(nfield < FIELD_LAST, 0); + + if (nfield < 0) + nfield = tuple_get_nfield(field); + + TUPLE_LOCK_READ(); + if (nfield < 0) + value = mowgli_dictionary_retrieve(tuple->dict, field); + else + value = tuple->values[nfield]; + + if (value) { + if (value->type != TUPLE_INT) + mowgli_throw_exception_val(audacious.tuple.invalid_type_request, 0); + + TUPLE_UNLOCK_READ(); + return value->value.integer; + } else { + TUPLE_UNLOCK_READ(); + return 0; + } +}