87
96
#define RHYTHMDB_TREE_XML_VERSION "1.0"
89
#define RHYTHMDB_TREE_ENTRY_VALUE(ENTRY, PROPID) (&((ENTRY)->properties[PROPID]))
90
#define RHYTHMDB_TREE_ENTRY_GET_TYPE(ENTRY) (g_value_get_int (RHYTHMDB_TREE_ENTRY_VALUE (ENTRY, RHYTHMDB_PROP_TYPE)))
92
#ifndef G_DISABLE_ASSERT
93
static inline RhythmDBTreeProperty *
94
assert_valid_tree_property (RhythmDBTreeProperty *prop)
96
g_assert (((RhythmDBTreeProperty *) prop)->magic == 0xf00dbeef);
99
#define RHYTHMDB_TREE_PROPERTY(x) (assert_valid_tree_property (x))
101
#define RHYTHMDB_TREE_PROPERTY(x) ((RhythmdbTreeProperty *) x)
104
#ifndef G_DISABLE_ASSERT
105
static inline RhythmDBTreeEntry *
106
assert_valid_tree_entry (RhythmDBTreeEntry *entry)
108
g_assert (((RhythmDBTreeEntry *) entry)->magic == 0xdeadb33f);
111
#define RHYTHMDB_TREE_ENTRY(x) (assert_valid_tree_entry (x))
113
#define RHYTHMDB_TREE_ENTRY(x) ((RhythmDBEntry *) x)
116
static RhythmDBEntry *rhythmdb_tree_entry_allocate (RhythmDBTree *db, RhythmDBEntryType type);
117
static gboolean rhythmdb_tree_entry_insert (RhythmDBTree *db, RhythmDBTreeEntry *entry,
118
RhythmDBEntryType type, const char *uri,
119
const char *genrename, const char *artistname,
120
const char *albumname);
122
98
static void destroy_tree_property (RhythmDBTreeProperty *prop);
123
99
static RhythmDBTreeProperty *get_or_create_album (RhythmDBTree *db, RhythmDBTreeProperty *artist,
125
101
static RhythmDBTreeProperty *get_or_create_artist (RhythmDBTree *db, RhythmDBTreeProperty *genre,
127
static inline RhythmDBTreeProperty *get_or_create_genre (RhythmDBTree *db, RhythmDBEntryType type,
130
static void rhythmdb_tree_entry_finalize (RhythmDBTreeEntry *entry);
131
static void remove_entry_from_album (RhythmDBTree *db, RhythmDBTreeEntry *entry);
133
static char *get_entry_genre_name (RhythmDBTreeEntry *entry);
134
static char *get_entry_artist_name (RhythmDBTreeEntry *entry);
135
static char *get_entry_album_name (RhythmDBTreeEntry *entry);
136
static char *get_entry_genre_sort_key (RhythmDBTreeEntry *entry);
137
static char *get_entry_artist_sort_key (RhythmDBTreeEntry *entry);
138
static char *get_entry_album_sort_key (RhythmDBTreeEntry *entry);
139
static char *get_entry_genre_folded (RhythmDBTreeEntry *entry);
140
static char *get_entry_artist_folded (RhythmDBTreeEntry *entry);
141
static char *get_entry_album_folded (RhythmDBTreeEntry *entry);
143
static void handle_genre_deletion (RhythmDBTree *db, const char *name);
144
static void handle_artist_deletion (RhythmDBTree *db, const char *name);
145
static void handle_album_deletion (RhythmDBTree *db, const char *name);
103
static RhythmDBTreeProperty *get_or_create_genre (RhythmDBTree *db, RhythmDBEntryType type,
106
static void remove_entry_from_album (RhythmDBTree *db, RhythmDBEntry *entry);
147
108
static GList *split_query_by_disjunctions (RhythmDBTree *db, GPtrArray *query);
148
109
static gboolean evaluate_conjunctive_subquery (RhythmDBTree *db, GPtrArray *query,
149
guint base, guint max, RhythmDBTreeEntry *entry);
110
guint base, guint max, RhythmDBEntry *entry);
151
112
struct RhythmDBTreePrivate
153
GMemChunk *entry_memchunk;
154
114
GMemChunk *property_memchunk;
156
116
GHashTable *entries;
485
320
case RHYTHMDB_TREE_PARSER_STATE_ENTRY:
487
RhythmDBEntryType type;
490
type = RHYTHMDB_TREE_ENTRY_GET_TYPE (ctx->entry);
492
uri = g_value_get_string (RHYTHMDB_TREE_ENTRY_VALUE (ctx->entry,
493
RHYTHMDB_PROP_LOCATION));
494
rhythmdb_write_lock ((RhythmDB *) ctx->db);
495
/* Ignore duplicate entries */
496
if (rhythmdb_tree_entry_lookup_by_location ((RhythmDB *) ctx->db, uri) == NULL) {
497
rhythmdb_tree_entry_insert (ctx->db, ctx->entry, type,
498
uri, ctx->genrename, ctx->artistname,
500
rhythmdb_emit_entry_restored ((RhythmDB *) ctx->db, ctx->entry);
322
if (!ctx->has_date) {
323
/* there is no date metadata, so this is from an old version
324
* reset the last-modified timestamp, so that the file is re-read
326
rb_debug ("pre-Date entry found, causing re-read");
327
ctx->entry->mtime = 0;
503
g_free (ctx->genrename);
504
g_free (ctx->artistname);
505
g_free (ctx->albumname);
507
rhythmdb_write_unlock (RHYTHMDB (ctx->db));
329
rhythmdb_tree_entry_new (RHYTHMDB (ctx->db), ctx->entry);
330
rhythmdb_entry_insert (RHYTHMDB (ctx->db), ctx->entry);
331
rhythmdb_commit (RHYTHMDB (ctx->db));
509
332
ctx->state = RHYTHMDB_TREE_PARSER_STATE_RHYTHMDB;
512
335
case RHYTHMDB_TREE_PARSER_STATE_ENTRY_PROPERTY:
514
GValue *value = RHYTHMDB_TREE_ENTRY_VALUE (ctx->entry, ctx->propid);
516
337
/* Handle indexed properties. */
517
338
switch (ctx->propid)
340
case RHYTHMDB_PROP_TYPE:
341
g_assert_not_reached ();
343
case RHYTHMDB_PROP_TITLE:
344
ctx->entry->title = rb_refstring_new (ctx->buf->str);
519
346
case RHYTHMDB_PROP_GENRE:
520
ctx->genrename = ctx->buf->str;
521
g_string_free (ctx->buf, FALSE);
347
ctx->entry->genre = rb_refstring_new (ctx->buf->str);
523
349
case RHYTHMDB_PROP_ARTIST:
524
ctx->artistname = ctx->buf->str;
525
g_string_free (ctx->buf, FALSE);
350
ctx->entry->artist = rb_refstring_new (ctx->buf->str);
527
352
case RHYTHMDB_PROP_ALBUM:
528
ctx->albumname = ctx->buf->str;
529
g_string_free (ctx->buf, FALSE);
535
/* Other properties */
536
g_value_reset (value);
538
/* Optimization possibility - don't use strtoull? We don't need
540
switch (G_VALUE_TYPE (value))
353
ctx->entry->album = rb_refstring_new (ctx->buf->str);
355
case RHYTHMDB_PROP_TRACK_NUMBER:
356
ctx->entry->tracknum = parse_ulong (ctx->buf->str);
358
case RHYTHMDB_PROP_DISC_NUMBER:
359
ctx->entry->discnum = parse_ulong (ctx->buf->str);
361
case RHYTHMDB_PROP_DATE:
543
g_value_set_string_take_ownership (value, ctx->buf->str);
544
g_string_free (ctx->buf, FALSE);
547
g_value_set_boolean (value, g_ascii_strtoull (ctx->buf->str, NULL, 10));
548
g_string_free (ctx->buf, TRUE);
551
g_value_set_int (value, g_ascii_strtoull (ctx->buf->str, NULL, 10));
552
g_string_free (ctx->buf, TRUE);
555
g_value_set_long (value, g_ascii_strtoull (ctx->buf->str, NULL, 10));
556
g_string_free (ctx->buf, TRUE);
559
g_value_set_uint64 (value, g_ascii_strtoull (ctx->buf->str, NULL, 10));
560
g_string_free (ctx->buf, TRUE);
563
g_value_set_float (value, g_ascii_strtod (ctx->buf->str, NULL));
564
g_string_free (ctx->buf, TRUE);
567
g_value_set_double (value, g_ascii_strtod (ctx->buf->str, NULL));
568
g_string_free (ctx->buf, TRUE);
363
gulong value = parse_ulong (ctx->buf->str);
366
ctx->entry->date = g_date_new_julian (value);
369
ctx->has_date = TRUE;
372
case RHYTHMDB_PROP_DURATION:
373
ctx->entry->duration = parse_ulong (ctx->buf->str);
375
case RHYTHMDB_PROP_FILE_SIZE:
376
ctx->entry->file_size = parse_ulong (ctx->buf->str);
378
case RHYTHMDB_PROP_LOCATION:
379
ctx->entry->location = g_strdup (ctx->buf->str);
381
case RHYTHMDB_PROP_MOUNTPOINT:
382
/* remove this from old podcast-post entries */
383
if (!g_str_has_prefix (ctx->buf->str, "http://"))
384
ctx->entry->mountpoint = rb_refstring_new (ctx->buf->str);
386
case RHYTHMDB_PROP_MTIME:
387
ctx->entry->mtime = parse_ulong (ctx->buf->str);
389
case RHYTHMDB_PROP_FIRST_SEEN:
390
ctx->entry->first_seen = parse_ulong (ctx->buf->str);
392
case RHYTHMDB_PROP_LAST_SEEN:
393
ctx->entry->last_seen = parse_ulong (ctx->buf->str);
395
case RHYTHMDB_PROP_RATING:
396
ctx->entry->rating = g_ascii_strtod (ctx->buf->str, NULL);
398
case RHYTHMDB_PROP_PLAY_COUNT:
399
ctx->entry->play_count = parse_ulong (ctx->buf->str);
401
case RHYTHMDB_PROP_LAST_PLAYED:
402
ctx->entry->last_played = parse_ulong (ctx->buf->str);
404
case RHYTHMDB_PROP_BITRATE:
405
ctx->entry->bitrate = parse_ulong (ctx->buf->str);
407
case RHYTHMDB_PROP_TRACK_GAIN:
408
ctx->entry->track_gain = g_ascii_strtod (ctx->buf->str, NULL);
410
case RHYTHMDB_PROP_TRACK_PEAK:
411
ctx->entry->track_peak = g_ascii_strtod (ctx->buf->str, NULL);
413
case RHYTHMDB_PROP_ALBUM_GAIN:
414
ctx->entry->album_gain = g_ascii_strtod (ctx->buf->str, NULL);
416
case RHYTHMDB_PROP_ALBUM_PEAK:
417
ctx->entry->album_peak = g_ascii_strtod (ctx->buf->str, NULL);
419
case RHYTHMDB_PROP_MIMETYPE:
420
ctx->entry->mimetype = rb_refstring_new (ctx->buf->str);
422
case RHYTHMDB_PROP_STATUS:
423
ctx->entry->podcast->status = parse_ulong (ctx->buf->str);
425
case RHYTHMDB_PROP_DESCRIPTION:
426
ctx->entry->podcast->description = rb_refstring_new (ctx->buf->str);
428
case RHYTHMDB_PROP_SUBTITLE:
429
ctx->entry->podcast->subtitle = rb_refstring_new (ctx->buf->str);
431
case RHYTHMDB_PROP_SUMMARY:
432
ctx->entry->podcast->summary = rb_refstring_new (ctx->buf->str);
434
case RHYTHMDB_PROP_LANG:
435
ctx->entry->podcast->lang = rb_refstring_new (ctx->buf->str);
437
case RHYTHMDB_PROP_COPYRIGHT:
438
ctx->entry->podcast->copyright = rb_refstring_new (ctx->buf->str);
440
case RHYTHMDB_PROP_IMAGE:
441
ctx->entry->podcast->image = rb_refstring_new (ctx->buf->str);
443
case RHYTHMDB_PROP_POST_TIME:
444
ctx->entry->podcast->post_time = parse_ulong (ctx->buf->str);
446
case RHYTHMDB_PROP_TITLE_SORT_KEY:
447
case RHYTHMDB_PROP_GENRE_SORT_KEY:
448
case RHYTHMDB_PROP_ARTIST_SORT_KEY:
449
case RHYTHMDB_PROP_ALBUM_SORT_KEY:
450
case RHYTHMDB_PROP_TITLE_FOLDED:
451
case RHYTHMDB_PROP_GENRE_FOLDED:
452
case RHYTHMDB_PROP_ARTIST_FOLDED:
453
case RHYTHMDB_PROP_ALBUM_FOLDED:
454
case RHYTHMDB_PROP_LAST_PLAYED_STR:
455
case RHYTHMDB_PROP_HIDDEN:
456
case RHYTHMDB_PROP_PLAYBACK_ERROR:
457
case RHYTHMDB_PROP_FIRST_SEEN_STR:
458
case RHYTHMDB_PROP_SEARCH_MATCH:
459
case RHYTHMDB_NUM_PROPERTIES:
571
460
g_assert_not_reached ();
574
rhythmdb_entry_sync_mirrored (RHYTHMDB (ctx->db),
575
ctx->entry, ctx->propid, value);
464
rhythmdb_entry_sync_mirrored (RHYTHMDB (ctx->db), ctx->entry, ctx->propid);
578
466
ctx->state = RHYTHMDB_TREE_PARSER_STATE_ENTRY;
646
536
RhythmDBTree *db;
541
#ifdef HAVE_GNU_FWRITE_UNLOCKED
542
#define RHYTHMDB_FWRITE_REAL fwrite_unlocked
543
#define RHYTHMDB_FPUTC_REAL fputc_unlocked
545
#define RHYTHMDB_FWRITE_REAL fwrite
546
#define RHYTHMDB_FPUTC_REAL fputc
549
#define RHYTHMDB_FWRITE(w,x,len,handle,error) do { \
550
if (error == NULL) { \
551
if (RHYTHMDB_FWRITE_REAL (w,x,len,handle) != len) { \
552
error = g_strdup (g_strerror (errno)); \
557
#define RHYTHMDB_FPUTC(x,handle,error) do { \
558
if (error == NULL) { \
559
if (RHYTHMDB_FPUTC_REAL (x,handle) == EOF) { \
560
error = g_strdup (g_strerror (errno)); \
565
#define RHYTHMDB_FWRITE_STATICSTR(STR, HANDLE, ERROR) RHYTHMDB_FWRITE(STR, 1, sizeof(STR)-1, HANDLE, ERROR)
568
write_elt_name_open (struct RhythmDBTreeSaveContext *ctx, const xmlChar *elt_name)
570
RHYTHMDB_FWRITE_STATICSTR (" <", ctx->handle, ctx->error);
571
RHYTHMDB_FWRITE (elt_name, 1, xmlStrlen (elt_name), ctx->handle, ctx->error);
572
RHYTHMDB_FPUTC ('>', ctx->handle, ctx->error);
576
write_elt_name_close (struct RhythmDBTreeSaveContext *ctx, const xmlChar *elt_name)
578
RHYTHMDB_FWRITE_STATICSTR ("</", ctx->handle, ctx->error);
579
RHYTHMDB_FWRITE (elt_name, 1, xmlStrlen (elt_name), ctx->handle, ctx->error);
580
RHYTHMDB_FWRITE_STATICSTR (">\n", ctx->handle, ctx->error);
584
save_entry_string (struct RhythmDBTreeSaveContext *ctx,
585
const xmlChar *elt_name, const char *str)
589
g_return_if_fail (str != NULL);
590
write_elt_name_open (ctx, elt_name);
591
encoded = xmlEncodeEntitiesReentrant (NULL, BAD_CAST str);
592
RHYTHMDB_FWRITE (encoded, 1, xmlStrlen (encoded), ctx->handle, ctx->error);
594
write_elt_name_close (ctx, elt_name);
598
save_entry_int (struct RhythmDBTreeSaveContext *ctx,
599
const xmlChar *elt_name, int num)
604
write_elt_name_open (ctx, elt_name);
605
g_snprintf (buf, sizeof (buf), "%d", num);
606
RHYTHMDB_FWRITE (buf, 1, strlen (buf), ctx->handle, ctx->error);
607
write_elt_name_close (ctx, elt_name);
611
save_entry_ulong (struct RhythmDBTreeSaveContext *ctx,
612
const xmlChar *elt_name, gulong num, gboolean save_zeroes)
615
if (num == 0 && !save_zeroes)
617
write_elt_name_open (ctx, elt_name);
618
g_snprintf (buf, sizeof (buf), "%lu", num);
619
RHYTHMDB_FWRITE (buf, 1, strlen (buf), ctx->handle, ctx->error);
620
write_elt_name_close (ctx, elt_name);
624
save_entry_uint64 (struct RhythmDBTreeSaveContext *ctx, const xmlChar *elt_name,
632
write_elt_name_open (ctx, elt_name);
633
g_snprintf (buf, sizeof (buf), "%" G_GUINT64_FORMAT, num);
634
RHYTHMDB_FWRITE (buf, 1, strlen (buf), ctx->handle, ctx->error);
635
write_elt_name_close (ctx, elt_name);
639
save_entry_double (struct RhythmDBTreeSaveContext *ctx,
640
const xmlChar *elt_name, double num)
644
if (num > -0.001 && num < 0.001)
647
write_elt_name_open (ctx, elt_name);
648
g_snprintf (buf, sizeof (buf), "%f", num);
649
RHYTHMDB_FWRITE (buf, 1, strlen (buf), ctx->handle, ctx->error);
650
write_elt_name_close (ctx, elt_name);
650
653
/* This code is intended to be highly optimized. This came at a small
651
654
* readability cost. Sorry about that.
654
save_entry (RhythmDBTree *db, RhythmDBTreeEntry *entry, struct RhythmDBTreeSaveContext *ctx)
657
save_entry (RhythmDBTree *db, RhythmDBEntry *entry, struct RhythmDBTreeSaveContext *ctx)
656
#ifdef HAVE_GNU_FWRITE_UNLOCKED
657
#define RHYTHMDB_FWRITE fwrite_unlocked
658
#define RHYTHMDB_FPUTC fputc_unlocked
660
#define RHYTHMDB_FWRITE fwrite
661
#define RHYTHMDB_FPUTC fputc
664
#define RHYTHMDB_FWRITE_STATICSTR(STR, F) RHYTHMDB_FWRITE (STR, 1, sizeof (STR)-1, F)
665
#define RHYTHMDB_FWRITE_SMALLTYPE(F, FMT, TYPE) \
667
g_snprintf (small_buf, sizeof (small_buf), \
668
FMT, g_value_get_ ## TYPE (value)); \
669
RHYTHMDB_FWRITE (small_buf, 1, strlen (small_buf), F); \
671
#define RHYTHMDB_FWRITE_ENCODED_STR(STR, F) \
674
encoded = xmlEncodeEntitiesReentrant (NULL, STR); \
675
RHYTHMDB_FWRITE (encoded, 1, strlen (encoded), F); \
679
659
RhythmDBPropType i;
681
RHYTHMDB_FWRITE_STATICSTR (" <entry type=\"", ctx->handle);
682
if (RHYTHMDB_TREE_ENTRY_GET_TYPE (entry) == RHYTHMDB_ENTRY_TYPE_SONG) {
683
RHYTHMDB_FWRITE_STATICSTR ("song", ctx->handle);
684
} else if (RHYTHMDB_TREE_ENTRY_GET_TYPE (entry) == RHYTHMDB_ENTRY_TYPE_IRADIO_STATION) {
685
RHYTHMDB_FWRITE_STATICSTR ("iradio", ctx->handle);
687
RHYTHMDB_FWRITE_STATICSTR ("\">\n", ctx->handle);
664
RHYTHMDB_FWRITE_STATICSTR (" <entry type=\"", ctx->handle, ctx->error);
666
if (entry->type == RHYTHMDB_ENTRY_TYPE_SONG) {
667
RHYTHMDB_FWRITE_STATICSTR ("song", ctx->handle, ctx->error);
668
} else if (entry->type == RHYTHMDB_ENTRY_TYPE_IRADIO_STATION) {
669
RHYTHMDB_FWRITE_STATICSTR ("iradio", ctx->handle, ctx->error);
670
} else if (entry->type == RHYTHMDB_ENTRY_TYPE_PODCAST_POST) {
671
RHYTHMDB_FWRITE_STATICSTR ("podcast-post", ctx->handle, ctx->error);
672
} else if (entry->type == RHYTHMDB_ENTRY_TYPE_PODCAST_FEED) {
673
RHYTHMDB_FWRITE_STATICSTR ("podcast-feed", ctx->handle, ctx->error);
675
g_assert_not_reached ();
677
RHYTHMDB_FWRITE_STATICSTR ("\">\n", ctx->handle, ctx->error);
689
679
/* Skip over the first property - the type */
690
for (i = 1; i < RHYTHMDB_NUM_SAVED_PROPERTIES; i++) {
691
const char *elt_name;
695
value = RHYTHMDB_TREE_ENTRY_VALUE (entry, i);
697
/* Optimization - don't save default values */
698
switch (G_VALUE_TYPE (value)) {
700
if (g_value_get_int (value) == 0)
704
if (g_value_get_long (value) == 0)
709
float v = g_value_get_float (value);
710
/* We don't care about precision so much. */
711
if (v > -0.001 && v < 0.001)
717
double v = g_value_get_double (value);
718
if (v > -0.001 && v < 0.001)
723
if (g_value_get_boolean (value) == FALSE)
680
for (i = 1; i < RHYTHMDB_NUM_PROPERTIES; i++) {
681
const xmlChar *elt_name;
728
686
elt_name = rhythmdb_nice_elt_name_from_propid ((RhythmDB *) ctx->db, i);
730
RHYTHMDB_FWRITE_STATICSTR (" <", ctx->handle);
731
RHYTHMDB_FWRITE (elt_name, 1, strlen (elt_name), ctx->handle);
732
RHYTHMDB_FPUTC ('>', ctx->handle);
734
/* Handle special properties. */
690
case RHYTHMDB_PROP_TYPE:
692
case RHYTHMDB_PROP_TITLE:
693
save_entry_string(ctx, elt_name, rb_refstring_get (entry->title));
737
695
case RHYTHMDB_PROP_ALBUM:
738
RHYTHMDB_FWRITE_ENCODED_STR(get_entry_album_name (entry), ctx->handle);
696
save_entry_string(ctx, elt_name, rb_refstring_get (entry->album));
740
698
case RHYTHMDB_PROP_ARTIST:
741
RHYTHMDB_FWRITE_ENCODED_STR(get_entry_artist_name (entry), ctx->handle);
699
save_entry_string(ctx, elt_name, rb_refstring_get (entry->artist));
743
701
case RHYTHMDB_PROP_GENRE:
744
RHYTHMDB_FWRITE_ENCODED_STR(get_entry_genre_name (entry), ctx->handle);
750
switch (G_VALUE_TYPE (value))
753
RHYTHMDB_FWRITE_ENCODED_STR(g_value_get_string (value), ctx->handle);
756
RHYTHMDB_FWRITE_SMALLTYPE (ctx->handle, "%d", boolean);
759
RHYTHMDB_FWRITE_SMALLTYPE (ctx->handle, "%d", int);
762
RHYTHMDB_FWRITE_SMALLTYPE (ctx->handle, "%ld", long);
765
RHYTHMDB_FWRITE_SMALLTYPE (ctx->handle, "%llu", uint64);
768
RHYTHMDB_FWRITE_SMALLTYPE (ctx->handle, "%f", float);
771
RHYTHMDB_FWRITE_SMALLTYPE (ctx->handle, "%f", double);
774
g_assert_not_reached ();
779
RHYTHMDB_FWRITE_STATICSTR ("</", ctx->handle);
780
RHYTHMDB_FWRITE (elt_name, 1, strlen (elt_name), ctx->handle);
781
RHYTHMDB_FWRITE_STATICSTR (">\n", ctx->handle);
702
save_entry_string(ctx, elt_name, rb_refstring_get (entry->genre));
704
case RHYTHMDB_PROP_TRACK_NUMBER:
705
save_entry_ulong (ctx, elt_name, entry->tracknum, FALSE);
707
case RHYTHMDB_PROP_DISC_NUMBER:
708
save_entry_ulong (ctx, elt_name, entry->discnum, FALSE);
710
case RHYTHMDB_PROP_DATE:
712
save_entry_ulong (ctx, elt_name, g_date_get_julian (entry->date), TRUE);
714
save_entry_ulong (ctx, elt_name, 0, TRUE);
716
case RHYTHMDB_PROP_DURATION:
717
save_entry_ulong (ctx, elt_name, entry->duration, FALSE);
719
case RHYTHMDB_PROP_BITRATE:
720
save_entry_int(ctx, elt_name, entry->bitrate);
722
case RHYTHMDB_PROP_TRACK_GAIN:
723
save_entry_double(ctx, elt_name, entry->track_gain);
725
case RHYTHMDB_PROP_TRACK_PEAK:
726
save_entry_double(ctx, elt_name, entry->track_peak);
728
case RHYTHMDB_PROP_ALBUM_GAIN:
729
save_entry_double(ctx, elt_name, entry->album_gain);
731
case RHYTHMDB_PROP_ALBUM_PEAK:
732
save_entry_double(ctx, elt_name, entry->album_peak);
734
case RHYTHMDB_PROP_LOCATION:
735
save_entry_string(ctx, elt_name, entry->location);
737
case RHYTHMDB_PROP_MOUNTPOINT:
738
/* Avoid crashes on exit when upgrading from 0.8
739
* and no mountpoint is available from some entries */
740
if (entry->mountpoint) {
741
save_entry_string(ctx, elt_name, rb_refstring_get (entry->mountpoint));
744
case RHYTHMDB_PROP_FILE_SIZE:
745
save_entry_uint64(ctx, elt_name, entry->file_size);
747
case RHYTHMDB_PROP_MIMETYPE:
748
save_entry_string(ctx, elt_name, rb_refstring_get (entry->mimetype));
750
case RHYTHMDB_PROP_MTIME:
751
save_entry_ulong (ctx, elt_name, entry->mtime, FALSE);
753
case RHYTHMDB_PROP_FIRST_SEEN:
754
save_entry_ulong (ctx, elt_name, entry->first_seen, FALSE);
756
case RHYTHMDB_PROP_LAST_SEEN:
757
save_entry_ulong (ctx, elt_name, entry->last_seen, FALSE);
759
case RHYTHMDB_PROP_RATING:
760
save_entry_double(ctx, elt_name, entry->rating);
762
case RHYTHMDB_PROP_PLAY_COUNT:
763
save_entry_ulong (ctx, elt_name, entry->play_count, FALSE);
765
case RHYTHMDB_PROP_LAST_PLAYED:
766
save_entry_ulong (ctx, elt_name, entry->last_played, FALSE);
768
case RHYTHMDB_PROP_STATUS:
770
save_entry_ulong (ctx, elt_name, entry->podcast->status, FALSE);
772
case RHYTHMDB_PROP_DESCRIPTION:
773
if (entry->podcast && entry->podcast->description)
774
save_entry_string(ctx, elt_name, rb_refstring_get (entry->podcast->description));
776
case RHYTHMDB_PROP_SUBTITLE:
777
if (entry->podcast && entry->podcast->subtitle)
778
save_entry_string(ctx, elt_name, rb_refstring_get (entry->podcast->subtitle));
780
case RHYTHMDB_PROP_SUMMARY:
781
if (entry->podcast && entry->podcast->summary)
782
save_entry_string(ctx, elt_name, rb_refstring_get (entry->podcast->summary));
784
case RHYTHMDB_PROP_LANG:
785
if (entry->podcast && entry->podcast->lang)
786
save_entry_string(ctx, elt_name, rb_refstring_get (entry->podcast->lang));
788
case RHYTHMDB_PROP_COPYRIGHT:
789
if (entry->podcast && entry->podcast->copyright)
790
save_entry_string(ctx, elt_name, rb_refstring_get (entry->podcast->copyright));
792
case RHYTHMDB_PROP_IMAGE:
793
if (entry->podcast && entry->podcast->image)
794
save_entry_string(ctx, elt_name, rb_refstring_get (entry->podcast->image));
796
case RHYTHMDB_PROP_POST_TIME:
798
save_entry_ulong (ctx, elt_name, entry->podcast->post_time, FALSE);
800
case RHYTHMDB_PROP_TITLE_SORT_KEY:
801
case RHYTHMDB_PROP_GENRE_SORT_KEY:
802
case RHYTHMDB_PROP_ARTIST_SORT_KEY:
803
case RHYTHMDB_PROP_ALBUM_SORT_KEY:
804
case RHYTHMDB_PROP_TITLE_FOLDED:
805
case RHYTHMDB_PROP_GENRE_FOLDED:
806
case RHYTHMDB_PROP_ARTIST_FOLDED:
807
case RHYTHMDB_PROP_ALBUM_FOLDED:
808
case RHYTHMDB_PROP_LAST_PLAYED_STR:
809
case RHYTHMDB_PROP_HIDDEN:
810
case RHYTHMDB_PROP_PLAYBACK_ERROR:
811
case RHYTHMDB_PROP_FIRST_SEEN_STR:
812
case RHYTHMDB_PROP_SEARCH_MATCH:
813
case RHYTHMDB_NUM_PROPERTIES:
783
RHYTHMDB_FWRITE_STATICSTR (" </entry>\n", ctx->handle);
785
#undef RHYTHMDB_FWRITE_ENCODED_STR
786
#undef RHYTHMDB_FWRITE_SMALLTYPE
787
#undef RHYTHMDB_FWRITE_STATICSTR
788
#undef RHYTHMDB_FPUTC
789
#undef RHYTHMDB_FWRITE
818
RHYTHMDB_FWRITE_STATICSTR (" </entry>\n", ctx->handle, ctx->error);
851
set_entry_album (RhythmDBTree *db, RhythmDBTreeEntry *entry, RhythmDBTreeProperty *artist,
854
entry->album = get_or_create_album (db, RHYTHMDB_TREE_PROPERTY (artist), name);
855
g_hash_table_insert (entry->album->children, RHYTHMDB_TREE_ENTRY (entry), NULL);
858
static RhythmDBEntry *
859
rhythmdb_tree_entry_allocate (RhythmDBTree *db, RhythmDBEntryType type)
861
RhythmDBTreeEntry *ret;
864
ret = g_mem_chunk_alloc0 (db->priv->entry_memchunk);
866
#ifndef G_DISABLE_ASSERT
867
ret->magic = 0xdeadb33f;
869
/* The refcount is initially 0, we want to set it to 1 */
870
rb_atomic_inc (&ret->refcount);
872
/* Initialize all the properties. */
873
for (i = 0; i < RHYTHMDB_NUM_PROPERTIES; i++) {
874
GType val_type = rhythmdb_get_property_type (RHYTHMDB (db), i);
875
g_value_init (RHYTHMDB_TREE_ENTRY_VALUE (ret, i), val_type);
877
/* Hack to ensure all string values are initialized. */
878
if (val_type == G_TYPE_STRING)
879
g_value_set_static_string (RHYTHMDB_TREE_ENTRY_VALUE (ret, i), "");
881
if (i == RHYTHMDB_PROP_TRACK_NUMBER)
882
g_value_set_int (RHYTHMDB_TREE_ENTRY_VALUE (ret, i), -1);
884
g_value_set_int (RHYTHMDB_TREE_ENTRY_VALUE (ret, RHYTHMDB_PROP_TYPE), type);
890
rhythmdb_tree_entry_insert (RhythmDBTree *db, RhythmDBTreeEntry *entry,
891
RhythmDBEntryType type,
893
const char *genrename, const char *artistname,
894
const char *albumname)
907
set_entry_album (RhythmDBTree *db, RhythmDBEntry *entry, RhythmDBTreeProperty *artist,
910
struct RhythmDBTreeProperty *prop;
911
prop = get_or_create_album (db, artist, name);
912
g_hash_table_insert (prop->children, entry, NULL);
917
rhythmdb_tree_entry_new (RhythmDB *rdb, RhythmDBEntry *entry)
919
RhythmDBTree *db = RHYTHMDB_TREE (rdb);
896
920
RhythmDBTreeProperty *artist;
897
921
RhythmDBTreeProperty *genre;
900
if (g_hash_table_lookup (db->priv->entries, uri))
923
g_assert (entry != NULL);
925
g_return_if_fail (entry->location != NULL);
927
if (entry->title == NULL) {
928
g_warning ("Entry %s has missing title",entry->location);
929
entry->title = rb_refstring_new (_("Unknown"));
931
if (entry->artist == NULL) {
932
g_warning ("Entry %s has missing artist",entry->location);
933
entry->artist = rb_refstring_new (_("Unknown"));
935
if (entry->album == NULL) {
936
g_warning ("Entry %s has missing album",entry->location);
937
entry->album = rb_refstring_new (_("Unknown"));
939
if (entry->genre == NULL) {
940
g_warning ("Entry %s has missing genre",entry->location);
941
entry->genre = rb_refstring_new (_("Unknown"));
943
if (entry->mimetype == NULL) {
944
g_warning ("Entry %s has missing mimetype",entry->location);
945
entry->mimetype = rb_refstring_new ("unknown/unknown");
903
948
/* Initialize the tree structure. */
904
genre = get_or_create_genre (db, type, genrename);
905
artist = get_or_create_artist (db, genre, artistname);
906
set_entry_album (db, entry, artist, albumname);
908
new_uri = g_strdup (uri);
910
g_hash_table_insert (db->priv->entries, new_uri, entry);
911
g_value_set_string_take_ownership (RHYTHMDB_TREE_ENTRY_VALUE (entry, RHYTHMDB_PROP_LOCATION),
917
static RhythmDBEntry *
918
rhythmdb_tree_entry_new (RhythmDB *rdb, RhythmDBEntryType type, const char *uri)
920
RhythmDBTree *db = RHYTHMDB_TREE (rdb);
921
RhythmDBTreeEntry *ret;
923
sanity_check_database (db);
925
ret = rhythmdb_tree_entry_allocate (db, type);
927
if (!rhythmdb_tree_entry_insert (db, ret, type, uri, "", "", "")) {
928
rhythmdb_tree_entry_destroy (db, ret);
932
sanity_check_database (db);
938
rhythmdb_tree_entry_destroy (RhythmDBTree *db, RhythmDBEntry *aentry)
940
RhythmDBTreeEntry *entry = RHYTHMDB_TREE_ENTRY (aentry);
941
rhythmdb_tree_entry_finalize (entry);
942
g_mem_chunk_free (db->priv->entry_memchunk, entry);
949
genre = get_or_create_genre (db, entry->type, entry->genre);
950
artist = get_or_create_artist (db, genre, entry->artist);
951
set_entry_album (db, entry, artist, entry->album);
953
g_hash_table_insert (db->priv->entries, entry->location, entry);
945
956
static RhythmDBTreeProperty *
946
rhythmdb_tree_property_new (RhythmDBTree *db, const char *name)
957
rhythmdb_tree_property_new (RhythmDBTree *db)
948
959
RhythmDBTreeProperty *ret = g_mem_chunk_alloc0 (db->priv->property_memchunk);
949
ret->name = g_strdup (name);
950
ret->sort_key = rb_get_sort_key (ret->name);
951
ret->folded = g_utf8_casefold (ret->name, -1);
952
960
#ifndef G_DISABLE_ASSERT
953
961
ret->magic = 0xf00dbeef;
958
static inline GHashTable *
959
967
get_genres_hash_for_type (RhythmDBTree *db, RhythmDBEntryType type)
961
969
GHashTable *table;
963
971
table = g_hash_table_lookup (db->priv->genres, GINT_TO_POINTER (type));
964
972
if (table == NULL) {
965
table = g_hash_table_new_full (g_str_hash, g_str_equal,
966
(GDestroyNotify) g_free,
973
table = g_hash_table_new_full (rb_refstring_hash,
975
(GDestroyNotify) rb_refstring_unref,
968
977
if (table == NULL) {
969
978
g_warning ("Out of memory\n");
1014
1024
genre = g_hash_table_lookup (table, name);
1016
1026
if (G_UNLIKELY (genre == NULL)) {
1017
genre = rhythmdb_tree_property_new (db, name);
1018
genre->children = g_hash_table_new_full (g_str_hash, g_str_equal,
1019
(GDestroyNotify) g_free,
1027
genre = rhythmdb_tree_property_new (db);
1028
genre->children = g_hash_table_new_full (rb_refstring_hash, rb_refstring_equal,
1029
(GDestroyNotify) rb_refstring_unref,
1021
g_hash_table_insert (table, g_strdup (name), genre);
1031
rb_refstring_ref (name);
1032
g_hash_table_insert (table, name, genre);
1022
1033
genre->parent = NULL;
1023
/* rhythmdb_emit_genre_added (RHYTHMDB (db), name); */
1026
return RHYTHMDB_TREE_PROPERTY (genre);
1029
1039
static RhythmDBTreeProperty *
1030
1040
get_or_create_artist (RhythmDBTree *db, RhythmDBTreeProperty *genre,
1033
1043
RhythmDBTreeProperty *artist;
1035
artist = g_hash_table_lookup (RHYTHMDB_TREE_PROPERTY (genre)->children, name);
1045
artist = g_hash_table_lookup (genre->children, name);
1037
1047
if (G_UNLIKELY (artist == NULL)) {
1038
artist = rhythmdb_tree_property_new (db, name);
1039
artist->children = g_hash_table_new_full (g_str_hash, g_str_equal,
1040
(GDestroyNotify) g_free,
1048
artist = rhythmdb_tree_property_new (db);
1049
artist->children = g_hash_table_new_full (rb_refstring_hash, rb_refstring_equal,
1050
(GDestroyNotify) rb_refstring_unref,
1042
g_hash_table_insert (genre->children, g_strdup (name), artist);
1052
rb_refstring_ref (name);
1053
g_hash_table_insert (genre->children, name, artist);
1043
1054
artist->parent = genre;
1044
/* rhythmdb_emit_artist_added (RHYTHMDB (db), name); */
1047
return RHYTHMDB_TREE_PROPERTY (artist);
1050
1060
static RhythmDBTreeProperty *
1051
1061
get_or_create_album (RhythmDBTree *db, RhythmDBTreeProperty *artist,
1054
1064
RhythmDBTreeProperty *album;
1056
album = g_hash_table_lookup (RHYTHMDB_TREE_PROPERTY (artist)->children, name);
1066
album = g_hash_table_lookup (artist->children, name);
1058
1068
if (G_UNLIKELY (album == NULL)) {
1059
album = rhythmdb_tree_property_new (db, name);
1069
album = rhythmdb_tree_property_new (db);
1060
1070
album->children = g_hash_table_new (g_direct_hash, g_direct_equal);
1061
g_hash_table_insert (artist->children, g_strdup (name), album);
1071
rb_refstring_ref (name);
1072
g_hash_table_insert (artist->children, name, album);
1062
1073
album->parent = artist;
1063
/* rhythmdb_emit_album_added (RHYTHMDB (db), name); */
1066
return RHYTHMDB_TREE_PROPERTY (album);
1070
handle_genre_deletion (RhythmDBTree *db, const char *name)
1072
/* if (!db->priv->finalizing) */
1073
/* rhythmdb_emit_genre_deleted (RHYTHMDB (db), name); */
1077
handle_artist_deletion (RhythmDBTree *db, const char *name)
1079
/* if (!db->priv->finalizing) */
1080
/* rhythmdb_emit_artist_deleted (RHYTHMDB (db), name); */
1084
handle_album_deletion (RhythmDBTree *db, const char *name)
1086
/* if (!db->priv->finalizing) */
1087
/* rhythmdb_emit_album_deleted (RHYTHMDB (db), name); */
1090
1079
static gboolean
1091
remove_child (RhythmDBTreeProperty *parent, gpointer entry)
1080
remove_child (RhythmDBTreeProperty *parent, gconstpointer data)
1093
RHYTHMDB_TREE_PROPERTY (parent);
1094
g_assert (g_hash_table_remove (parent->children, entry));
1082
g_assert (g_hash_table_remove (parent->children, data));
1095
1083
if (g_hash_table_size (parent->children) <= 0) {
1102
remove_entry_from_album (RhythmDBTree *db, RhythmDBTreeEntry *entry)
1090
remove_entry_from_album (RhythmDBTree *db, RhythmDBEntry *entry)
1104
char *cur_albumname;
1105
char *cur_artistname;
1106
char *cur_genrename;
1107
1092
GHashTable *table;
1109
cur_albumname = g_strdup (get_entry_album_name (entry));
1110
cur_artistname = g_strdup (get_entry_artist_name (entry));
1111
cur_genrename = g_strdup (get_entry_genre_name (entry));
1113
table = get_genres_hash_for_type (db, RHYTHMDB_TREE_ENTRY_GET_TYPE (entry));
1114
if (remove_child (RHYTHMDB_TREE_PROPERTY (entry->album), entry)) {
1116
handle_album_deletion (db, cur_albumname);
1118
if (remove_child (RHYTHMDB_TREE_PROPERTY (entry->album->parent), cur_albumname)) {
1119
handle_artist_deletion (db, cur_artistname);
1121
if (remove_child (RHYTHMDB_TREE_PROPERTY (entry->album->parent->parent),
1123
handle_genre_deletion (db, cur_albumname);
1124
destroy_tree_property (entry->album->parent->parent);
1125
g_hash_table_remove (table, cur_genrename);
1094
rb_refstring_ref (entry->genre);
1095
rb_refstring_ref (entry->artist);
1096
rb_refstring_ref (entry->album);
1098
table = get_genres_hash_for_type (db, entry->type);
1099
if (remove_child (RHYTHMDB_TREE_PROPERTY_FROM_ENTRY (entry), entry)) {
1100
if (remove_child (RHYTHMDB_TREE_PROPERTY_FROM_ENTRY (entry)->parent,
1103
if (remove_child (RHYTHMDB_TREE_PROPERTY_FROM_ENTRY (entry)->parent->parent,
1105
destroy_tree_property (RHYTHMDB_TREE_PROPERTY_FROM_ENTRY (entry)->parent->parent);
1106
g_assert (g_hash_table_remove (table, entry->genre));
1127
destroy_tree_property (entry->album->parent);
1108
destroy_tree_property (RHYTHMDB_TREE_PROPERTY_FROM_ENTRY (entry)->parent);
1130
destroy_tree_property (entry->album);
1111
destroy_tree_property (RHYTHMDB_TREE_PROPERTY_FROM_ENTRY (entry));
1133
g_free (cur_genrename);
1134
g_free (cur_artistname);
1135
g_free (cur_albumname);
1114
rb_refstring_unref (entry->genre);
1115
rb_refstring_unref (entry->artist);
1116
rb_refstring_unref (entry->album);
1139
rhythmdb_tree_entry_set (RhythmDB *adb, RhythmDBEntry *aentry,
1120
rhythmdb_tree_entry_set (RhythmDB *adb, RhythmDBEntry *entry,
1140
1121
guint propid, const GValue *value)
1142
1123
RhythmDBTree *db = RHYTHMDB_TREE (adb);
1143
RhythmDBTreeEntry *entry = RHYTHMDB_TREE_ENTRY (aentry);
1144
1124
RhythmDBEntryType type;
1146
type = RHYTHMDB_TREE_ENTRY_GET_TYPE (entry);
1148
sanity_check_database (db);
1153
1128
/* Handle special properties */
1154
1129
switch (propid)
1131
case RHYTHMDB_PROP_LOCATION:
1133
/* We have to use the string in the entry itself as the hash key,
1134
* otherwise either we leak it, or the string vanishes when the
1135
* GValue is freed; this means we have to do the entry modification
1136
* here, rather than letting rhythmdb_entry_set_internal do it.
1138
g_assert (g_hash_table_lookup (db->priv->entries, entry->location) != NULL);
1140
g_hash_table_remove (db->priv->entries, entry->location);
1142
g_free (entry->location);
1143
entry->location = g_strdup (g_value_get_string (value));
1144
g_hash_table_insert (db->priv->entries, entry->location, entry);
1156
1148
case RHYTHMDB_PROP_ALBUM:
1158
1150
const char *albumname = g_value_get_string (value);
1160
if (strcmp (get_entry_album_name (entry), albumname)) {
1161
char *cur_genrename, *cur_artistname;
1152
if (strcmp (rb_refstring_get (entry->album), albumname)) {
1162
1153
RhythmDBTreeProperty *artist;
1163
1154
RhythmDBTreeProperty *genre;
1165
cur_artistname = g_strdup (get_entry_artist_name (entry));
1166
cur_genrename = g_strdup (get_entry_genre_name (entry));
1156
rb_refstring_ref (entry->genre);
1157
rb_refstring_ref (entry->artist);
1158
rb_refstring_ref (entry->album);
1168
1160
remove_entry_from_album (db, entry);
1170
genre = RHYTHMDB_TREE_PROPERTY (get_or_create_genre (db, type, cur_genrename));
1171
artist = RHYTHMDB_TREE_PROPERTY (get_or_create_artist (db, genre, cur_artistname));
1172
set_entry_album (db, entry, artist, albumname);
1174
sanity_check_entry_tree (entry);
1176
g_free (cur_artistname);
1177
g_free (cur_genrename);
1162
genre = get_or_create_genre (db, type, entry->genre);
1163
artist = get_or_create_artist (db, genre, entry->artist);
1164
set_entry_album (db, entry, artist, rb_refstring_new (albumname));
1166
rb_refstring_unref (entry->genre);
1167
rb_refstring_unref (entry->artist);
1168
rb_refstring_unref (entry->album);
1181
1172
case RHYTHMDB_PROP_ARTIST:
1183
1174
const char *artistname = g_value_get_string (value);
1184
char *cur_artistname = get_entry_artist_name (entry);
1186
if (strcmp (cur_artistname, artistname)) {
1176
if (strcmp (rb_refstring_get (entry->artist), artistname)) {
1187
1177
RhythmDBTreeProperty *new_artist;
1188
1178
RhythmDBTreeProperty *genre;
1189
char *cur_genrename, *cur_albumname;
1191
cur_artistname = g_strdup (cur_artistname);
1192
cur_albumname = g_strdup (get_entry_album_name (entry));
1193
cur_genrename = g_strdup (get_entry_genre_name (entry));
1180
rb_refstring_ref (entry->genre);
1181
rb_refstring_ref (entry->artist);
1182
rb_refstring_ref (entry->album);
1195
1184
remove_entry_from_album (db, entry);
1197
genre = RHYTHMDB_TREE_PROPERTY (get_or_create_genre (db, type, cur_genrename));
1198
new_artist = RHYTHMDB_TREE_PROPERTY (get_or_create_artist (db, genre, artistname));
1200
set_entry_album (db, entry, new_artist, cur_albumname);
1202
sanity_check_entry_tree (entry);
1204
g_free (cur_genrename);
1205
g_free (cur_albumname);
1206
g_free (cur_artistname);
1186
genre = get_or_create_genre (db, type, entry->genre);
1187
new_artist = get_or_create_artist (db, genre,
1188
rb_refstring_new (artistname));
1189
set_entry_album (db, entry, new_artist, entry->album);
1191
rb_refstring_unref (entry->genre);
1192
rb_refstring_unref (entry->artist);
1193
rb_refstring_unref (entry->album);
1210
1197
case RHYTHMDB_PROP_GENRE:
1212
1199
const char *genrename = g_value_get_string (value);
1213
char *cur_genrename = get_entry_genre_name (entry);
1215
if (strcmp (cur_genrename, genrename)) {
1201
if (strcmp (rb_refstring_get (entry->genre), genrename)) {
1216
1202
RhythmDBTreeProperty *new_genre;
1217
1203
RhythmDBTreeProperty *new_artist;
1221
cur_genrename = g_strdup (cur_genrename);
1223
artistname = g_strdup (get_entry_artist_name (entry));
1224
albumname = g_strdup (get_entry_album_name (entry));
1205
rb_refstring_ref (entry->genre);
1206
rb_refstring_ref (entry->artist);
1207
rb_refstring_ref (entry->album);
1226
1209
remove_entry_from_album (db, entry);
1228
new_genre = RHYTHMDB_TREE_PROPERTY (get_or_create_genre (db, type, genrename));
1229
new_artist = RHYTHMDB_TREE_PROPERTY (get_or_create_artist (db, new_genre, artistname));
1231
set_entry_album (db, entry, new_artist, albumname);
1233
sanity_check_entry_tree (entry);
1235
g_free (cur_genrename);
1236
g_free (artistname);
1211
new_genre = get_or_create_genre (db, type,
1212
rb_refstring_new (genrename));
1213
new_artist = get_or_create_artist (db, new_genre, entry->artist);
1214
set_entry_album (db, entry, new_artist, entry->album);
1216
rb_refstring_unref (entry->genre);
1217
rb_refstring_unref (entry->artist);
1218
rb_refstring_unref (entry->album);
1242
g_value_reset (RHYTHMDB_TREE_ENTRY_VALUE (entry, propid));
1243
g_value_copy (value, RHYTHMDB_TREE_ENTRY_VALUE (entry, propid));
1247
sanity_check_database (db);
1251
rhythmdb_tree_entry_get (RhythmDB *adb, RhythmDBEntry *aentry,
1252
guint propid, GValue *value)
1254
RhythmDBTree *db = RHYTHMDB_TREE (adb);
1255
RhythmDBTreeEntry *entry = RHYTHMDB_TREE_ENTRY (aentry);
1257
sanity_check_database (db);
1259
if (G_UNLIKELY (entry->deleted)) {
1260
g_value_copy (RHYTHMDB_TREE_ENTRY_VALUE (entry, propid), value);
1266
/* Handle special properties */
1267
case RHYTHMDB_PROP_ALBUM:
1268
g_value_set_static_string (value, get_entry_album_name (entry));
1270
case RHYTHMDB_PROP_ARTIST:
1271
g_value_set_static_string (value, get_entry_artist_name (entry));
1273
case RHYTHMDB_PROP_GENRE:
1274
g_value_set_static_string (value, get_entry_genre_name (entry));
1276
case RHYTHMDB_PROP_ALBUM_SORT_KEY:
1277
g_value_set_static_string (value, get_entry_album_sort_key (entry));
1279
case RHYTHMDB_PROP_ARTIST_SORT_KEY:
1280
g_value_set_static_string (value, get_entry_artist_sort_key (entry));
1282
case RHYTHMDB_PROP_GENRE_SORT_KEY:
1283
g_value_set_static_string (value, get_entry_genre_sort_key (entry));
1285
case RHYTHMDB_PROP_ALBUM_FOLDED:
1286
g_value_set_static_string (value, get_entry_album_folded (entry));
1288
case RHYTHMDB_PROP_ARTIST_FOLDED:
1289
g_value_set_static_string (value, get_entry_artist_folded (entry));
1291
case RHYTHMDB_PROP_GENRE_FOLDED:
1292
g_value_set_static_string (value, get_entry_genre_folded (entry));
1294
/* Handle other string properties */
1295
case RHYTHMDB_PROP_TITLE:
1296
g_value_set_static_string (value, g_value_get_string (RHYTHMDB_TREE_ENTRY_VALUE (entry, RHYTHMDB_PROP_TITLE)));
1298
case RHYTHMDB_PROP_TITLE_SORT_KEY:
1299
g_value_set_static_string (value, g_value_get_string (RHYTHMDB_TREE_ENTRY_VALUE (entry, RHYTHMDB_PROP_TITLE_SORT_KEY)));
1301
case RHYTHMDB_PROP_LOCATION:
1302
g_value_set_static_string (value, g_value_get_string (RHYTHMDB_TREE_ENTRY_VALUE (entry, RHYTHMDB_PROP_LOCATION)));
1304
case RHYTHMDB_PROP_LAST_PLAYED_STR:
1305
g_value_set_static_string (value, g_value_get_string (RHYTHMDB_TREE_ENTRY_VALUE (entry, RHYTHMDB_PROP_LAST_PLAYED_STR)));
1307
case RHYTHMDB_PROP_TRACK_GAIN:
1308
g_value_set_double (value, g_value_get_double (RHYTHMDB_TREE_ENTRY_VALUE (entry, RHYTHMDB_PROP_TRACK_GAIN)));
1310
case RHYTHMDB_PROP_TRACK_PEAK:
1311
g_value_set_double (value, g_value_get_double (RHYTHMDB_TREE_ENTRY_VALUE (entry, RHYTHMDB_PROP_TRACK_PEAK)));
1313
case RHYTHMDB_PROP_ALBUM_GAIN:
1314
g_value_set_double (value, g_value_get_double (RHYTHMDB_TREE_ENTRY_VALUE (entry, RHYTHMDB_PROP_ALBUM_GAIN)));
1316
case RHYTHMDB_PROP_ALBUM_PEAK:
1317
g_value_set_double (value, g_value_get_double (RHYTHMDB_TREE_ENTRY_VALUE (entry, RHYTHMDB_PROP_ALBUM_PEAK)));
1320
g_value_copy (RHYTHMDB_TREE_ENTRY_VALUE (entry, propid), value);
1324
sanity_check_database (RHYTHMDB_TREE (db));
1328
rhythmdb_tree_entry_finalize (RhythmDBTreeEntry *entry)
1331
for (i = 0; i < RHYTHMDB_NUM_PROPERTIES; i++) {
1332
g_value_unset (RHYTHMDB_TREE_ENTRY_VALUE (entry, i));
1334
#ifndef G_DISABLE_ASSERT
1335
entry->magic = 0xf33df33d;
1340
rhythmdb_tree_entry_delete_real (RhythmDB *adb, RhythmDBEntry *aentry)
1342
RhythmDBTree *db = RHYTHMDB_TREE (adb);
1343
RhythmDBTreeEntry *entry = RHYTHMDB_TREE_ENTRY (aentry);
1348
entry->deleted = TRUE;
1351
/* We store these properties back in the entry temporarily so that later
1352
callbacks can retreive the value even though the entry is removed from
1355
g_value_set_string (RHYTHMDB_TREE_ENTRY_VALUE (entry, RHYTHMDB_PROP_GENRE),
1356
get_entry_genre_name (entry));
1357
g_value_set_string (RHYTHMDB_TREE_ENTRY_VALUE (entry, RHYTHMDB_PROP_ARTIST),
1358
get_entry_artist_name (entry));
1359
g_value_set_string (RHYTHMDB_TREE_ENTRY_VALUE (entry, RHYTHMDB_PROP_ALBUM),
1360
get_entry_album_name (entry));
1230
rhythmdb_tree_entry_delete (RhythmDB *adb, RhythmDBEntry *entry)
1232
RhythmDBTree *db = RHYTHMDB_TREE (adb);
1361
1234
remove_entry_from_album (db, entry);
1365
rhythmdb_tree_entry_delete (RhythmDB *adb, RhythmDBEntry *aentry)
1367
RhythmDBTree *db = RHYTHMDB_TREE (adb);
1368
RhythmDBTreeEntry *entry = RHYTHMDB_TREE_ENTRY (aentry);
1371
sanity_check_database (db);
1373
rhythmdb_tree_entry_delete_real (adb, aentry);
1375
uri = g_value_get_string (RHYTHMDB_TREE_ENTRY_VALUE (entry, RHYTHMDB_PROP_LOCATION));
1376
g_assert (g_hash_table_lookup (db->priv->entries, uri) != NULL);
1378
g_hash_table_remove (db->priv->entries, uri);
1380
sanity_check_database (db);
1236
g_assert (g_hash_table_lookup (db->priv->entries, entry->location) != NULL);
1238
g_hash_table_remove (db->priv->entries, entry->location);
1383
1241
typedef struct {
1421
case RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN:
1422
case RHYTHMDB_QUERY_PROP_CURRENT_TIME_NOT_WITHIN:
1424
gulong relative_time;
1425
GTimeVal current_time;
1427
g_assert (rhythmdb_get_property_type (db, data->propid) == G_TYPE_ULONG);
1429
relative_time = g_value_get_ulong (data->val);
1430
g_get_current_time (¤t_time);
1432
if (data->type == RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN)
1433
return (rhythmdb_entry_get_ulong (entry, data->propid) >= (current_time.tv_sec - relative_time));
1435
return (rhythmdb_entry_get_ulong (entry, data->propid) < (current_time.tv_sec - relative_time));
1499
1439
case RHYTHMDB_QUERY_PROP_LIKE:
1500
1440
case RHYTHMDB_QUERY_PROP_NOT_LIKE:
1501
if (G_VALUE_TYPE (data->val) == G_TYPE_STRING) {
1442
if (rhythmdb_get_property_type (db, data->propid) == G_TYPE_STRING) {
1502
1443
gboolean islike;
1503
const char *stra, *strb;
1505
switch (data->propid)
1507
case RHYTHMDB_PROP_ALBUM_FOLDED:
1508
stra = get_entry_album_folded (entry);
1510
case RHYTHMDB_PROP_ARTIST_FOLDED:
1511
stra = get_entry_artist_folded (entry);
1513
case RHYTHMDB_PROP_GENRE_FOLDED:
1514
stra = get_entry_genre_folded (entry);
1517
stra = g_value_get_string (RHYTHMDB_TREE_ENTRY_VALUE (entry, data->propid));
1445
if (data->propid == RHYTHMDB_PROP_SEARCH_MATCH) {
1446
/* this is a special property, that should match several things */
1447
islike = search_match_properties (db, entry, g_value_get_boxed (data->val));
1450
const gchar *value_string = g_value_get_string (data->val);
1451
const char *entry_string = rhythmdb_entry_get_string (entry, data->propid);
1453
/* check in case the property is NULL, the value should never be NULL */
1454
if (entry_string == NULL)
1457
islike = (strstr (entry_string, value_string) != NULL);
1520
strb = g_value_get_string (data->val);
1521
islike = (strstr (stra, strb) != NULL);
1522
if (data->type == RHYTHMDB_QUERY_PROP_LIKE
1525
else if (data->type == RHYTHMDB_QUERY_PROP_NOT_LIKE
1529
if (rb_gvalue_compare (RHYTHMDB_TREE_ENTRY_VALUE (entry, data->propid),
1460
if ((data->type == RHYTHMDB_QUERY_PROP_LIKE) ^ islike)
1534
1468
case RHYTHMDB_QUERY_PROP_EQUALS:
1535
switch (data->propid)
1537
case RHYTHMDB_PROP_ALBUM:
1538
if (strcmp (get_entry_album_name (entry),
1539
g_value_get_string (data->val)))
1542
case RHYTHMDB_PROP_ARTIST:
1543
if (strcmp (get_entry_artist_name (entry),
1544
g_value_get_string (data->val)))
1547
case RHYTHMDB_PROP_GENRE:
1548
if (strcmp (get_entry_genre_name (entry),
1549
g_value_get_string (data->val)))
1553
if (rb_gvalue_compare (RHYTHMDB_TREE_ENTRY_VALUE (entry, data->propid),
1470
RHYTHMDB_PROPERTY_COMPARE (!=)
1559
1473
case RHYTHMDB_QUERY_PROP_GREATER:
1560
if (rb_gvalue_compare (RHYTHMDB_TREE_ENTRY_VALUE (entry, data->propid),
1474
RHYTHMDB_PROPERTY_COMPARE (<)
1564
1476
case RHYTHMDB_QUERY_PROP_LESS:
1565
if (rb_gvalue_compare (RHYTHMDB_TREE_ENTRY_VALUE (entry, data->propid),
1477
RHYTHMDB_PROPERTY_COMPARE (>)
1569
1479
case RHYTHMDB_QUERY_END:
1570
1480
case RHYTHMDB_QUERY_DISJUNCTION: