static gboolean queue_track_to_scrobble (gpointer data) { AUDDBG("The playing track is going to be ENQUEUED!\n."); gchar *tab_remover; char *queuepath = g_strconcat(aud_get_path(AUD_PATH_USER_DIR),"/scrobbler.log", NULL); char *artist = tuple_get_str(playing_track, FIELD_ARTIST); char *title = tuple_get_str(playing_track, FIELD_TITLE); char *album = tuple_get_str(playing_track, FIELD_ALBUM); tab_remover = remove_tabs(artist); str_unref(artist); artist = tab_remover; tab_remover = remove_tabs(title); str_unref(title); title = tab_remover; tab_remover = remove_tabs(album); str_unref(album); album = tab_remover; tab_remover = NULL; int number = tuple_get_int(playing_track, FIELD_TRACK_NUMBER); int length = tuple_get_int(playing_track, FIELD_LENGTH) / 1000; //artist, title and timestamp are required for a successful scrobble if ( artist != NULL && strlen(artist) > 0 && title != NULL && strlen(title) > 0) { pthread_mutex_lock(&log_access_mutex); FILE *f = fopen(queuepath, "a"); if (f == NULL) { perror("fopen"); } else { //This isn't exactly the scrobbler.log format because the header //is missing, but we're sticking to it anyway... //See http://www.audioscrobbler.net/wiki/Portable_Player_Logging if (fprintf(f, "%s\t%s\t%s\t%i\t%i\t%s\t%"G_GINT64_FORMAT"\n", artist, (album == NULL ? "" : album), title, number, length, "L", timestamp ) < 0) { perror("fprintf"); } else { pthread_mutex_lock(&communication_mutex); pthread_cond_signal(&communication_signal); pthread_mutex_unlock(&communication_mutex); } fclose(f); } pthread_mutex_unlock(&log_access_mutex); } g_free(queuepath); g_free(artist); g_free(title); g_free(album); cleanup_current_track(); return FALSE; }
static char * strdup_tuple_filename (const Tuple * tuple) { gchar * fpath = tuple_get_str (tuple, FIELD_FILE_PATH, NULL); gchar * fname = tuple_get_str (tuple, FIELD_FILE_NAME, NULL); gchar * filename = g_strdup_printf ("%s/%s", fpath, fname); str_unref (fpath); str_unref (fname); return filename; }
static void insert_vorbis_comment (FLAC__StreamMetadata * meta, const char * name, const Tuple * tuple, int field) { TupleValueType type = tuple_field_get_type (field); if (tuple_get_value_type (tuple, field, NULL) != type) return; char * temp; switch (type) { case TUPLE_INT:; int ival = tuple_get_int (tuple, field, NULL); temp = g_strdup_printf ("%s=%d", name, ival); break; case TUPLE_STRING:; char * sval = tuple_get_str (tuple, field, NULL); temp = g_strdup_printf ("%s=%s", name, sval); str_unref (sval); default: return; } FLAC__StreamMetadata_VorbisComment_Entry comment; comment.length = strlen (temp); comment.entry = (unsigned char *) temp; FLAC__metadata_object_vorbiscomment_insert_comment (meta, meta->data.vorbis_comment.num_comments, comment, TRUE); g_free (temp); }
static void set_string_from_tuple (GValue * value, const Tuple * tuple, gint field) { gchar *str = tuple ? tuple_get_str (tuple, field, NULL) : NULL; g_value_set_string (value, str); str_unref(str); }
static void add_frameFromTupleStr (const Tuple * tuple, int field, int id3_field, GHashTable * dict) { char * str = tuple_get_str (tuple, field); add_text_frame (id3_field, str, dict); str_unref (str); }
static bool_t audpl_save (const char * path, VFSFile * file, const char * title, Index * filenames, Index * tuples) { if (! write_key (file, "title", title)) return FALSE; int count = index_count (filenames); for (int i = 0; i < count; i ++) { if (! write_key (file, "uri", index_get (filenames, i))) return FALSE; const Tuple * tuple = tuples ? index_get (tuples, i) : NULL; if (tuple) { int keys = 0; for (int f = 0; f < TUPLE_FIELDS; f ++) { if (f == FIELD_FILE_PATH || f == FIELD_FILE_NAME || f == FIELD_FILE_EXT) continue; TupleValueType type = tuple_get_value_type (tuple, f, NULL); if (type == TUPLE_STRING) { char * str = tuple_get_str (tuple, f, NULL); if (! write_key (file, tuple_field_get_name (f), str)) { str_unref (str); return FALSE; } str_unref (str); keys ++; } else if (type == TUPLE_INT) { char buf[32]; snprintf (buf, sizeof buf, "%d", tuple_get_int (tuple, f, NULL)); if (! write_key (file, tuple_field_get_name (f), buf)) return FALSE; keys ++; } } /* distinguish between an empty tuple and no tuple at all */ if (! keys && ! write_key (file, "empty", "1")) return FALSE; } } return TRUE; }
static bool_t id3v24_write_tag (const Tuple * tuple, VFSFile * f) { int version, header_size, data_size, footer_size; bool_t syncsafe; int64_t offset; if (! read_header (f, & version, & syncsafe, & offset, & header_size, & data_size, & footer_size)) return FALSE; //read all frames into generic frames; GHashTable * dict = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) str_unref, (GDestroyNotify) free_frame_list); read_all_frames (f, version, syncsafe, data_size, dict); //make the new frames from tuple and replace in the dictionary the old frames with the new ones add_frameFromTupleStr (tuple, FIELD_TITLE, ID3_TITLE, dict); add_frameFromTupleStr (tuple, FIELD_ARTIST, ID3_ARTIST, dict); add_frameFromTupleStr (tuple, FIELD_ALBUM, ID3_ALBUM, dict); add_frameFromTupleInt (tuple, FIELD_YEAR, ID3_YEAR, dict); add_frameFromTupleInt (tuple, FIELD_TRACK_NUMBER, ID3_TRACKNR, dict); add_frameFromTupleStr (tuple, FIELD_GENRE, ID3_GENRE, dict); char * comment = tuple_get_str (tuple, FIELD_COMMENT); add_comment_frame (comment, dict); str_unref (comment); if (! offset) { if (! cut_beginning_tag (f, header_size + data_size + footer_size)) goto ERR; } else { if (offset + header_size + data_size + footer_size != vfs_fsize (f)) goto ERR; if (vfs_ftruncate (f, offset)) goto ERR; } offset = vfs_fsize (f); if (offset < 0 || vfs_fseek (f, offset, SEEK_SET) || ! write_header (f, 0, FALSE)) goto ERR; data_size = write_all_frames (f, dict); if (! write_header (f, data_size, TRUE) || vfs_fseek (f, offset, SEEK_SET) || ! write_header (f, data_size, FALSE)) goto ERR; g_hash_table_destroy (dict); return TRUE; ERR: g_hash_table_destroy (dict); return FALSE; }
static int tuple_compare_string (const Tuple * a, const Tuple * b, int field) { char * string_a = tuple_get_str (a, field, NULL); char * string_b = tuple_get_str (b, field, NULL); int ret; if (string_a == NULL) ret = (string_b == NULL) ? 0 : -1; else if (string_b == NULL) ret = 1; else ret = string_compare (string_a, string_b); str_unref (string_a); str_unref (string_b); return ret; }
static void infowin_show (int list, int entry, const char * filename, const Tuple * tuple, PluginHandle * decoder, bool_t updating_enabled) { char * tmp; 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 = uri_to_display (filename); gtk_label_set_text ((GtkLabel *) location_text, 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_str (tuple, FIELD_CODEC, NULL)); infowin_label_set_text (label_quality, tuple_get_str (tuple, FIELD_QUALITY, NULL)); if (tuple_get_value_type (tuple, FIELD_BITRATE, NULL) == TUPLE_INT) infowin_label_set_text (label_bitrate, str_printf (_("%d kb/s"), tuple_get_int (tuple, FIELD_BITRATE, NULL))); else infowin_label_set_text (label_bitrate, NULL); infowin_entry_set_image (image_artwork, list, entry); gtk_window_present ((GtkWindow *) infowin); }
static void set_entry_str_from_field (GtkWidget * widget, const Tuple * tuple, int fieldn, bool_t editable) { char * text = tuple_get_str (tuple, fieldn, NULL); gtk_entry_set_text ((GtkEntry *) widget, text != NULL ? text : ""); gtk_editable_set_editable ((GtkEditable *) widget, editable); str_unref (text); }
static void add_string_from_tuple (vorbis_comment * vc, const char * name, const Tuple * tuple, gint field) { gchar * val = tuple_get_str (tuple, field, NULL); if (! val) return; vorbis_comment_add_tag (vc, name, val); str_unref (val); }
void playlist_select_by_patterns (int playlist, const Tuple * patterns) { const int fields[] = {FIELD_TITLE, FIELD_ALBUM, FIELD_ARTIST, FIELD_FILE_NAME}; int entries = playlist_entry_count (playlist); int field, entry; playlist_select_all (playlist, TRUE); for (field = 0; field < G_N_ELEMENTS (fields); field ++) { char * pattern = tuple_get_str (patterns, fields[field], NULL); regex_t regex; if (! pattern || ! pattern[0] || regcomp (& regex, pattern, REG_ICASE)) { str_unref (pattern); continue; } for (entry = 0; entry < entries; entry ++) { if (! playlist_entry_get_selected (playlist, entry)) continue; Tuple * tuple = playlist_entry_get_tuple (playlist, entry, FALSE); char * string = tuple ? tuple_get_str (tuple, fields[field], NULL) : NULL; if (! string || regexec (& regex, string, 0, NULL, 0)) playlist_entry_set_selected (playlist, entry, FALSE); str_unref (string); if (tuple) tuple_unref (tuple); } regfree (& regex); str_unref (pattern); } }
static void insert_str_tuple_field_to_dictionary (const Tuple * tuple, int fieldn, GHashTable * dict, const char * key) { char * val = tuple_get_str (tuple, fieldn); if (val && val[0]) g_hash_table_insert (dict, str_get (key), str_ref (val)); else g_hash_table_remove (dict, key); str_unref(val); }
static char * get_nonblank_field (const Tuple * tuple, int field) { char * str = tuple ? tuple_get_str (tuple, field, NULL) : NULL; if (str && ! str[0]) { str_unref (str); str = NULL; } return str; }
static void add_text (Tuple * tuple, int field, const char * value) { char * cur = tuple_get_str (tuple, field, NULL); if (cur) { SPRINTF (both, "%s, %s", cur, value); tuple_set_str (tuple, field, NULL, both); } else tuple_set_str (tuple, field, NULL, value); str_unref(cur); }
static void insert_str_tuple_to_vc (FLAC__StreamMetadata * vc_block, const Tuple * tuple, int tuple_name, char * field_name) { FLAC__StreamMetadata_VorbisComment_Entry entry; char *val = tuple_get_str(tuple, tuple_name, NULL); if (val == NULL) return; SPRINTF (str, "%s=%s", field_name, val); entry.entry = (FLAC__byte *) str; entry.length = strlen(str); FLAC__metadata_object_vorbiscomment_insert_comment(vc_block, vc_block->data.vorbis_comment.num_comments, entry, true); str_unref(val); }
static char * strdup_tuple_field (const Tuple * tuple, int field) { char * sval, * dup; int ival; switch (tuple_get_value_type (tuple, field, NULL)) { case TUPLE_INT: ival = tuple_get_int (tuple, field, NULL); dup = g_strdup_printf ("%d", ival); break; case TUPLE_STRING: sval = tuple_get_str (tuple, field, NULL); dup = g_strdup (sval); str_unref (sval); break; default: dup = NULL; break; } return dup; }
static gint mp3_open(void) { int imp3; gfp = lame_init(); if (gfp == NULL) return 0; /* setup id3 data */ id3tag_init(gfp); if (tuple) { /* XXX write UTF-8 even though libmp3lame does id3v2.3. --yaz */ lameid3.track_name = tuple_get_str (tuple, FIELD_TITLE, NULL); id3tag_set_title(gfp, lameid3.track_name); lameid3.performer = tuple_get_str (tuple, FIELD_ARTIST, NULL); id3tag_set_artist(gfp, lameid3.performer); lameid3.album_name = tuple_get_str (tuple, FIELD_ALBUM, NULL); id3tag_set_album(gfp, lameid3.album_name); lameid3.genre = tuple_get_str (tuple, FIELD_GENRE, NULL); id3tag_set_genre(gfp, lameid3.genre); lameid3.year = str_printf ("%d", tuple_get_int (tuple, FIELD_YEAR, NULL)); id3tag_set_year(gfp, lameid3.year); lameid3.track_number = str_printf ("%d", tuple_get_int (tuple, FIELD_TRACK_NUMBER, NULL)); id3tag_set_track(gfp, lameid3.track_number); if (force_v2_val) { id3tag_add_v2(gfp); } if (only_v1_val) { id3tag_v1_only(gfp); } if (only_v2_val) { id3tag_v2_only(gfp); } } /* input stream description */ lame_set_in_samplerate(gfp, input.frequency); lame_set_num_channels(gfp, input.channels); /* Maybe implement this? */ /* lame_set_scale(lame_global_flags *, float); */ lame_set_out_samplerate(gfp, out_samplerate_val); /* general control parameters */ lame_set_bWriteVbrTag(gfp, toggle_xing_val); lame_set_quality(gfp, algo_quality_val); if (audio_mode_val != 4) { AUDDBG("set mode to %d\n", audio_mode_val); lame_set_mode(gfp, audio_mode_val); } lame_set_errorf(gfp, lame_debugf); lame_set_debugf(gfp, lame_debugf); lame_set_msgf(gfp, lame_debugf); if (enc_toggle_val == 0 && vbr_on == 0) lame_set_brate(gfp, bitrate_val); else if (vbr_on == 0) lame_set_compression_ratio(gfp, compression_val); /* frame params */ lame_set_copyright(gfp, mark_copyright_val); lame_set_original(gfp, mark_original_val); lame_set_error_protection(gfp, error_protect_val); lame_set_strict_ISO(gfp, enforce_iso_val); if (vbr_on != 0) { if (vbr_type == 0) lame_set_VBR(gfp, 2); else lame_set_VBR(gfp, 3); lame_set_VBR_q(gfp, vbr_quality_val); lame_set_VBR_mean_bitrate_kbps(gfp, abr_val); lame_set_VBR_min_bitrate_kbps(gfp, vbr_min_val); lame_set_VBR_max_bitrate_kbps(gfp, vbr_max_val); lame_set_VBR_hard_min(gfp, enforce_min_val); } /* not to write id3 tag automatically. */ lame_set_write_id3tag_automatic(gfp, 0); if (lame_init_params(gfp) == -1) return 0; /* write id3v2 header */ imp3 = lame_get_id3v2_tag(gfp, encbuffer, sizeof(encbuffer)); if (imp3 > 0) { write_output(encbuffer, imp3); id3v2_size = imp3; } else { id3v2_size = 0; } write_buffer = NULL; write_buffer_size = 0; return 1; }
/* do_command(): do @cmd after replacing the format codes @cmd: command to run */ static void do_command (char * cmd) { int playlist = aud_playlist_get_playing (); int pos = aud_playlist_get_position (playlist); char *shstring = NULL, *temp, numbuf[32]; gboolean playing; Formatter *formatter; if (cmd && strlen(cmd) > 0) { formatter = formatter_new(); char * ctitle = aud_playlist_entry_get_title (playlist, pos, FALSE); if (ctitle) { temp = escape_shell_chars (ctitle); formatter_associate(formatter, 's', temp); formatter_associate(formatter, 'n', temp); g_free(temp); str_unref (ctitle); } else { formatter_associate(formatter, 's', ""); formatter_associate(formatter, 'n', ""); } char * filename = aud_playlist_entry_get_filename (playlist, pos); if (filename) { temp = escape_shell_chars (filename); formatter_associate(formatter, 'f', temp); g_free(temp); str_unref (filename); } else formatter_associate(formatter, 'f', ""); g_snprintf(numbuf, sizeof(numbuf), "%02d", pos + 1); formatter_associate(formatter, 't', numbuf); int length = aud_playlist_entry_get_length (playlist, pos, FALSE); if (length > 0) { g_snprintf(numbuf, sizeof(numbuf), "%d", length); formatter_associate(formatter, 'l', numbuf); } else formatter_associate(formatter, 'l', "0"); playing = aud_drct_get_playing(); g_snprintf(numbuf, sizeof(numbuf), "%d", playing); formatter_associate(formatter, 'p', numbuf); if (playing) { int brate, srate, chans; aud_drct_get_info (& brate, & srate, & chans); snprintf (numbuf, sizeof numbuf, "%d", brate); formatter_associate (formatter, 'r', numbuf); snprintf (numbuf, sizeof numbuf, "%d", srate); formatter_associate (formatter, 'F', numbuf); snprintf (numbuf, sizeof numbuf, "%d", chans); formatter_associate (formatter, 'c', numbuf); } Tuple * tuple = aud_playlist_entry_get_tuple (aud_playlist_get_active (), pos, 0); char * artist = tuple ? tuple_get_str (tuple, FIELD_ARTIST, NULL) : NULL; if (artist) { formatter_associate(formatter, 'a', artist); str_unref(artist); } else formatter_associate(formatter, 'a', ""); char * album = tuple ? tuple_get_str (tuple, FIELD_ALBUM, NULL) : NULL; if (album) { formatter_associate(formatter, 'b', album); str_unref(album); } else formatter_associate(formatter, 'b', ""); char * title = tuple ? tuple_get_str (tuple, FIELD_TITLE, NULL) : NULL; if (title) { formatter_associate(formatter, 'T', title); str_unref(title); } else formatter_associate(formatter, 'T', ""); if (tuple) tuple_unref (tuple); shstring = formatter_format(formatter, cmd); formatter_destroy(formatter); if (shstring) { execute_command(shstring); /* FIXME: This can possibly be freed too early */ g_free(shstring); } } }
static void send_now_playing() { gchar *error_code = NULL; gchar *error_detail = NULL; /* * now_playing_track can be set to something else while we this method is * running. Creating a local variable avoids to get data for different tracks, * while now_playing_track was updated concurrently. */ Tuple *curr_track = now_playing_track; gchar *tab_remover; gchar *artist = tuple_get_str(curr_track, FIELD_ARTIST, NULL); gchar *album = tuple_get_str(curr_track, FIELD_ALBUM, NULL); gchar *title = tuple_get_str(curr_track, FIELD_TITLE, NULL); tab_remover = remove_tabs(artist); str_unref(artist); artist = tab_remover; tab_remover = remove_tabs(album); str_unref(album); album = tab_remover; tab_remover = remove_tabs(title); str_unref(title); title = tab_remover; tab_remover = NULL; gchar *number = g_strdup_printf("%i", tuple_get_int(curr_track, FIELD_TRACK_NUMBER, NULL)); gchar *length = g_strdup_printf("%i", tuple_get_int(curr_track, FIELD_LENGTH, NULL) / 1000); tuple_unref(curr_track); if (artist != NULL && strlen(artist) > 0 && title != NULL && strlen(title) > 0) { gchar *playingmsg = create_message_to_lastfm("track.updateNowPlaying", 7, "artist", artist, "album", (album == NULL ? "" : album), "track", title, "trackNumber", number, "duration", length, "api_key", SCROBBLER_API_KEY, "sk", session_key); g_free(artist); g_free(album); g_free(title); g_free(number); g_free(length); bool_t success = send_message_to_lastfm(playingmsg); g_free(playingmsg); if (success == FALSE) { AUDDBG("Network problems. Could not send \"now playing\" to last.fm\n"); scrobbling_enabled = FALSE; return; } if (read_scrobble_result(&error_code, &error_detail) == TRUE) { //see scrobble_cached_queue() AUDDBG("NOW PLAYING OK.\n"); } else { AUDDBG("NOW PLAYING NOT OK. Error code: %s. Error detail: %s.\n", error_code, error_detail); //From the API: Now Playing requests that fail should not be retried. if (g_strcmp0(error_code, "9") == 0) { //Bad Session. Reauth. //We don't really care about any other errors. scrobbling_enabled = FALSE; g_free(session_key); session_key = NULL; aud_set_string("scrobbler", "session_key", ""); } } g_free(error_code); g_free(error_detail); //We don't care if the now playing was not accepted, no need to read the result from the server. } }
static gboolean update_song_tuple(const Tuple * tuple, VFSFile *file) { #if _AUD_PLUGIN_VERSION < 38 #define vfs_get_filename(file) g_filename_from_uri(file->uri, NULL, NULL) #define tuple_get_str tuple_get_string #define str_unref(s) const char *s; #else char *s; #endif /* read file */ const char *filename = vfs_get_filename(file); unsigned char module[ASAPInfo_MAX_MODULE_LENGTH]; int module_len = load_module(filename, file, module); ASAPInfo *info; int year; ByteWriter bw; gboolean ok; if (module_len <= 0) return FALSE; info = ASAPInfo_New(); if (info == NULL) return FALSE; if (!ASAPInfo_Load(info, filename, module, module_len)) { ASAPInfo_Delete(info); return FALSE; } /* apply new tags */ s = tuple_get_str(tuple, FIELD_ARTIST, NULL); if (s != NULL) { if (!ASAPInfo_SetAuthor(info, s)) { str_unref(s); ASAPInfo_Delete(info); return FALSE; } str_unref(s); } else ASAPInfo_SetAuthor(info, ""); s = tuple_get_str(tuple, FIELD_TITLE, NULL); if (s != NULL) { if (!ASAPInfo_SetTitle(info, s)) { str_unref(s); ASAPInfo_Delete(info); return FALSE; } str_unref(s); } else ASAPInfo_SetTitle(info, ""); year = tuple_get_int(tuple, FIELD_YEAR, NULL); if (year == 0) year = -1; /* check if year changed so that we don't lose other date parts */ if (year != ASAPInfo_GetYear(info)) { if (year <= 0) ASAPInfo_SetDate(info, ""); else { char d[16]; sprintf(d, "%d", year); ASAPInfo_SetDate(info, d); } } /* write file */ vfs_rewind(file); bw.obj = file; bw.func = write_byte; ok = ASAPWriter_Write(filename, bw, info, module, module_len, TRUE) && vfs_ftruncate(file, vfs_ftell(file)) == 0; ASAPInfo_Delete(info); return ok; }
static gboolean xspf_playlist_save (const gchar * filename, VFSFile * file, const gchar * title, Index * filenames, Index * tuples) { gint entries = index_count (filenames); xmlDocPtr doc; xmlNodePtr rootnode, tracklist; gint count; doc = xmlNewDoc((xmlChar *)"1.0"); doc->charset = XML_CHAR_ENCODING_UTF8; doc->encoding = xmlStrdup((xmlChar *)"UTF-8"); rootnode = xmlNewNode(NULL, (xmlChar *)XSPF_ROOT_NODE_NAME); xmlSetProp(rootnode, (xmlChar *)"version", (xmlChar *)"1"); xmlSetProp(rootnode, (xmlChar *)"xmlns", (xmlChar *)XSPF_XMLNS); /* common */ xmlDocSetRootElement(doc, rootnode); if (title) xspf_add_node (rootnode, TUPLE_STRING, FALSE, "title", title, 0); tracklist = xmlNewNode(NULL, (xmlChar *)"trackList"); xmlAddChild(rootnode, tracklist); for (count = 0; count < entries; count ++) { const gchar * filename = index_get (filenames, count); const Tuple * tuple = index_get (tuples, count); xmlNodePtr track, location; gchar *scratch = NULL; gint scratchi = 0; track = xmlNewNode(NULL, (xmlChar *)"track"); location = xmlNewNode(NULL, (xmlChar *)"location"); xmlAddChild(location, xmlNewText((xmlChar *)filename)); xmlAddChild(track, location); xmlAddChild(tracklist, track); if (tuple != NULL) { gint i; for (i = 0; i < xspf_nentries; i++) { const xspf_entry_t *xs = &xspf_entries[i]; gboolean isOK = (tuple_get_value_type (tuple, xs->tupleField, NULL) == xs->type); switch (xs->type) { case TUPLE_STRING: scratch = tuple_get_str (tuple, xs->tupleField, NULL); if (! scratch) isOK = FALSE; str_unref(scratch); break; case TUPLE_INT: scratchi = tuple_get_int (tuple, xs->tupleField, NULL); break; default: break; } if (isOK) xspf_add_node(track, xs->type, xs->isMeta, xs->xspfName, scratch, scratchi); } } } xmlSaveCtxt * save = xmlSaveToIO (write_cb, close_cb, file, NULL, XML_SAVE_FORMAT); if (! save) goto ERR; if (xmlSaveDoc (save, doc) < 0 || xmlSaveClose (save) < 0) goto ERR; xmlFreeDoc(doc); return TRUE; ERR: xmlFreeDoc (doc); return FALSE; }